<!DOCTYPE html>
<!-- saved from url=(0082)#t17012.3%20namespace -->
<html lang="en">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>珠峰</title>
    <link rel="stylesheet" type="text/css" href="./typescript6/main.css">
    <link rel="stylesheet" href="./typescript6/bootstrap.min.css">
    <script src="./1.js"></script>
    <style>
        .page-toc>ul .red {
            background: #f3f3f3;
            z-index: 1;
            border-left: 3px solid #009a61;
            -webkit-transition: all .2s ease;
            transition: all .2s ease;
            color: #000
        }
    </style>
</head>

<body>



    <div class="warpper">
        <div class="page-toc">
            <ul>
                <li><a href="#t01.%20typescript%E6%98%AF%E4%BB%80%E4%B9%88">1.
                        typescript是什么</a></li>
                <li><a href="#t12.%20TypeScript%E5%AE%89%E8%A3%85%E5%92%8C%E7%BC%96%E8%AF%91">2.
                        TypeScript安装和编译</a>
                    <ul>
                        <li><a href="#t22.1%20%E5%AE%89%E8%A3%85">2.1
                                安装</a></li>
                        <li><a href="#t32.2%20Vscode+TypeScript">2.2
                                Vscode+TypeScript</a>
                            <ul>
                                <li><a href="#t42.2.1%20%20%E7%94%9F%E6%88%90%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6">2.2.1
                                        生成配置文件</a></li>
                                <li><a href="#t52.2.2%20%E6%89%A7%E8%A1%8C%E7%BC%96%E8%AF%91">2.2.2
                                        执行编译</a></li>
                                <li><a href="#t62.2.3%20vscode%E8%BF%90%E8%A1%8C">2.2.3
                                        vscode运行</a></li>
                                <li><a href="#t72.2.4%20npm%20scripts">2.2.4
                                        npm scripts</a></li>
                                <li><a href="#t82.2.5%20npm%20scripts%20%E7%9A%84%20PATH">2.2.5
                                        npm scripts 的 PATH</a></li>
                            </ul>
                        </li>
                    </ul>
                </li>
                <li><a href="#t93.%20%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B">3.
                        数据类型</a>
                    <ul>
                        <li><a href="#t103.1%20%E5%B8%83%E5%B0%94%E7%B1%BB%E5%9E%8B(boolean)">3.1
                                布尔类型(boolean)</a></li>
                        <li><a href="#t113.2%20%E6%95%B0%E5%AD%97%E7%B1%BB%E5%9E%8B(number)">3.2
                                数字类型(number)</a></li>
                        <li><a href="#t123.3%20%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%B1%BB%E5%9E%8B(string)">3.3
                                字符串类型(string)</a></li>
                        <li><a href="#t133.4%20%E6%95%B0%E7%BB%84%E7%B1%BB%E5%9E%8B(array)">3.4
                                数组类型(array)</a></li>
                        <li><a href="#t143.5%20%E5%85%83%E7%BB%84%E7%B1%BB%E5%9E%8B(tuple)">3.5
                                元组类型(tuple)</a></li>
                        <li><a href="#t153.6%20%E6%9E%9A%E4%B8%BE%E7%B1%BB%E5%9E%8B(enum)">3.6
                                枚举类型(enum)</a>
                            <ul>
                                <li><a href="#t163.6.1%20%E6%99%AE%E9%80%9A%E6%9E%9A%E4%B8%BE">3.6.1
                                        普通枚举</a></li>
                                <li><a href="#t173.6.2%20%E5%B8%B8%E6%95%B0%E6%9E%9A%E4%B8%BE">3.6.2
                                        常数枚举</a></li>
                            </ul>
                        </li>
                        <li><a href="#t183.7%20%E4%BB%BB%E6%84%8F%E7%B1%BB%E5%9E%8B(any)">3.7
                                任意类型(any)</a></li>
                        <li><a href="#t193.8%20null%20%E5%92%8C%20undefined">3.8
                                null 和 undefined</a></li>
                        <li><a href="#t203.9%20void%20%E7%B1%BB%E5%9E%8B">3.9
                                void 类型</a></li>
                        <li><a href="#t213.10%20never%E7%B1%BB%E5%9E%8B">3.10
                                never类型</a>
                            <ul>
                                <li><a href="#t223.10.1">3.10.1</a>
                                </li>
                                <li><a href="#t233.10.2%20%20strictNullChecks">3.10.2
                                        strictNullChecks</a></li>
                                <li><a href="#t243.10.3%20%20never%20%E5%92%8C%20void%20%E7%9A%84%E5%8C%BA%E5%88%AB">3.10.3
                                        never 和 void 的区别</a></li>
                                <li><a href="#t253.11%20%20Symbol">3.11
                                        Symbol</a></li>
                                <li><a href="#t263.12%20%20BigInt">3.12
                                        BigInt</a></li>
                            </ul>
                        </li>
                        <li><a href="#t273.13%20%E7%B1%BB%E5%9E%8B%E6%8E%A8%E8%AE%BA">3.13
                                类型推论</a></li>
                        <li><a
                                href="#t283.14%20%20%E5%8C%85%E8%A3%85%E5%AF%B9%E8%B1%A1%EF%BC%88Wrapper%20Object%EF%BC%89">3.14
                                包装对象（Wrapper Object）</a></li>
                        <li><a href="#t293.15%20%E8%81%94%E5%90%88%E7%B1%BB%E5%9E%8B">3.15
                                联合类型</a></li>
                        <li><a href="#t303.16%20%E7%B1%BB%E5%9E%8B%E6%96%AD%E8%A8%80">3.16
                                类型断言</a></li>
                        <li><a
                                href="#t313.17%20%E5%AD%97%E9%9D%A2%E9%87%8F%E7%B1%BB%E5%9E%8B%E5%92%8C%E7%B1%BB%E5%9E%8B%E5%AD%97%E9%9D%A2%E9%87%8F">3.17
                                字面量类型和类型字面量</a></li>
                        <li><a
                                href="#t323.18%20%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%AD%97%E9%9D%A2%E9%87%8F%20vs%20%E8%81%94%E5%90%88%E7%B1%BB%E5%9E%8B">3.18
                                字符串字面量 vs 联合类型</a></li>
                    </ul>
                </li>
                <li><a href="#t334.%20%E5%87%BD%E6%95%B0">4.
                        函数</a>
                    <ul>
                        <li><a href="#t344.1%20%E5%87%BD%E6%95%B0%E7%9A%84%E5%AE%9A%E4%B9%89">4.1
                                函数的定义</a></li>
                        <li><a href="#t354.2%20%E5%87%BD%E6%95%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F">4.2
                                函数表达式</a></li>
                        <li><a href="#t364.3%20%E6%B2%A1%E6%9C%89%E8%BF%94%E5%9B%9E%E5%80%BC">4.3
                                没有返回值</a></li>
                        <li><a href="#t374.4%20%E5%8F%AF%E9%80%89%E5%8F%82%E6%95%B0">4.4
                                可选参数</a></li>
                        <li><a href="#t384.5%20%E9%BB%98%E8%AE%A4%E5%8F%82%E6%95%B0">4.5
                                默认参数</a></li>
                        <li><a href="#t394.6%20%E5%89%A9%E4%BD%99%E5%8F%82%E6%95%B0">4.6
                                剩余参数</a></li>
                        <li><a href="#t404.7%20%E5%87%BD%E6%95%B0%E9%87%8D%E8%BD%BD">4.7
                                函数重载</a></li>
                    </ul>
                </li>
                <li><a href="#t415.%20%E7%B1%BB">5. 类</a>
                    <ul>
                        <li><a href="#t425.1%20%E5%A6%82%E4%BD%95%E5%AE%9A%E4%B9%89%E7%B1%BB">5.1
                                如何定义类</a></li>
                        <li><a href="#t435.2%20%E5%AD%98%E5%8F%96%E5%99%A8">5.2
                                存取器</a></li>
                        <li><a href="#t445.3%20%E5%8F%82%E6%95%B0%E5%B1%9E%E6%80%A7">5.3
                                参数属性</a></li>
                        <li><a href="#t455.4%20readonly">5.4
                                readonly</a></li>
                        <li><a href="#t465.5%20%E7%BB%A7%E6%89%BF">5.5
                                继承</a></li>
                        <li><a href="#t475.6%20%E7%B1%BB%E9%87%8C%E9%9D%A2%E7%9A%84%E4%BF%AE%E9%A5%B0%E7%AC%A6">5.6
                                类里面的修饰符</a></li>
                        <li><a
                                href="#t485.7%20%E9%9D%99%E6%80%81%E5%B1%9E%E6%80%A7%20%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95">5.7
                                静态属性 静态方法</a></li>
                        <li><a href="#t495.8%20%E8%A3%85%E9%A5%B0%E5%99%A8">5.8
                                装饰器</a>
                            <ul>
                                <li><a href="#t505.8.1%20%E7%B1%BB%E8%A3%85%E9%A5%B0%E5%99%A8">5.8.1
                                        类装饰器</a></li>
                                <li><a href="#t515.8.2%20%E5%B1%9E%E6%80%A7%E8%A3%85%E9%A5%B0%E5%99%A8">5.8.2
                                        属性装饰器</a></li>
                                <li><a href="#t525.8.3%20%E5%8F%82%E6%95%B0%E8%A3%85%E9%A5%B0%E5%99%A8">5.8.3
                                        参数装饰器</a></li>
                                <li><a
                                        href="#t535.8.4%20%E8%A3%85%E9%A5%B0%E5%99%A8%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F">5.8.4
                                        装饰器执行顺序</a></li>
                            </ul>
                        </li>
                        <li><a href="#t545.9%20%E6%8A%BD%E8%B1%A1%E7%B1%BB">5.9
                                抽象类</a></li>
                        <li><a href="#t555.10%20%E6%8A%BD%E8%B1%A1%E6%96%B9%E6%B3%95">5.10
                                抽象方法</a></li>
                        <li><a href="#t565.11%20%E9%87%8D%E5%86%99(override)%20vs%20%E9%87%8D%E8%BD%BD(overload)">5.11
                                重写(override) vs 重载(overload)</a></li>
                        <li><a href="#t575.12%20%E7%BB%A7%E6%89%BF%20vs%20%E5%A4%9A%E6%80%81">5.12
                                继承 vs 多态</a></li>
                    </ul>
                </li>
                <li><a href="#t586.%20%E6%8E%A5%E5%8F%A3">6.
                        接口</a>
                    <ul>
                        <li><a href="#t596.1%20%E6%8E%A5%E5%8F%A3">6.1
                                接口</a>
                            <ul>
                                <li><a href="#t606.1.1%20%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%BD%A2%E7%8A%B6">6.1.1
                                        对象的形状</a></li>
                                <li><a href="#t616.1.2%20%E8%A1%8C%E4%B8%BA%E7%9A%84%E6%8A%BD%E8%B1%A1">6.1.2
                                        行为的抽象</a></li>
                                <li><a href="#t626.1.3%20%E4%BB%BB%E6%84%8F%E5%B1%9E%E6%80%A7">6.1.3
                                        任意属性</a></li>
                            </ul>
                        </li>
                        <li><a href="#t636.2%20%E6%8E%A5%E5%8F%A3%E7%9A%84%E7%BB%A7%E6%89%BF">6.2
                                接口的继承</a></li>
                        <li><a href="#t646.3%20readonly">6.3
                                readonly</a></li>
                        <li><a href="#t656.4%20%E5%87%BD%E6%95%B0%E7%B1%BB%E5%9E%8B%E6%8E%A5%E5%8F%A3">6.4
                                函数类型接口</a></li>
                        <li><a href="#t666.5%20%E5%8F%AF%E7%B4%A2%E5%BC%95%E6%8E%A5%E5%8F%A3">6.5
                                可索引接口</a></li>
                        <li><a href="#t676.6%20%E7%B1%BB%E6%8E%A5%E5%8F%A3">6.6
                                类接口</a></li>
                        <li><a href="#t686.7%20%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E7%9A%84%E7%B1%BB%E5%9E%8B">6.7
                                构造函数的类型</a></li>
                        <li><a href="#t696.8%20%20%E6%8A%BD%E8%B1%A1%E7%B1%BB%20vs%20%E6%8E%A5%E5%8F%A3">6.8
                                抽象类 vs 接口</a></li>
                    </ul>
                </li>
                <li><a href="#t707.%20%E6%B3%9B%E5%9E%8B">7.
                        泛型</a>
                    <ul>
                        <li><a href="#t717.1%20%E6%B3%9B%E5%9E%8B%E5%87%BD%E6%95%B0">7.1
                                泛型函数</a></li>
                        <li><a href="#t727.2%20%E7%B1%BB%E6%95%B0%E7%BB%84">7.2
                                类数组</a></li>
                        <li><a href="#t737.3%20%E6%B3%9B%E5%9E%8B%E7%B1%BB">7.3
                                泛型类</a>
                            <ul>
                                <li><a href="#t747.3.1%20%E6%B3%9B%E5%9E%8B%E7%B1%BB">7.3.1
                                        泛型类</a></li>
                                <li><a href="#t757.3.2%20%E6%B3%9B%E5%9E%8B%E4%B8%8E%20new">7.3.2
                                        泛型与 new</a></li>
                            </ul>
                        </li>
                        <li><a href="#t767.5%20%E6%B3%9B%E5%9E%8B%E6%8E%A5%E5%8F%A3">7.5
                                泛型接口</a></li>
                        <li><a href="#t777.6%20%E5%A4%9A%E4%B8%AA%E7%B1%BB%E5%9E%8B%E5%8F%82%E6%95%B0">7.6
                                多个类型参数</a></li>
                        <li><a href="#t787.7%20%E9%BB%98%E8%AE%A4%E6%B3%9B%E5%9E%8B%E7%B1%BB%E5%9E%8B">7.7
                                默认泛型类型</a></li>
                        <li><a href="#t797.8%20%E6%B3%9B%E5%9E%8B%E7%BA%A6%E6%9D%9F">7.8
                                泛型约束</a></li>
                        <li><a href="#t807.9%20%E6%B3%9B%E5%9E%8B%E6%8E%A5%E5%8F%A3">7.9
                                泛型接口</a></li>
                        <li><a href="#t817.10%20compose">7.10
                                compose</a></li>
                        <li><a href="#t827.11%20%E6%B3%9B%E5%9E%8B%E7%B1%BB%E5%9E%8B%E5%88%AB%E5%90%8D">7.11
                                泛型类型别名</a></li>
                        <li><a
                                href="#t837.12%20%E6%B3%9B%E5%9E%8B%E6%8E%A5%E5%8F%A3%20vs%20%E6%B3%9B%E5%9E%8B%E7%B1%BB%E5%9E%8B%E5%88%AB%E5%90%8D">7.12
                                泛型接口 vs 泛型类型别名</a></li>
                    </ul>
                </li>
                <li><a href="#t848.%E7%BB%93%E6%9E%84%E7%B1%BB%E5%9E%8B%E7%B3%BB%E7%BB%9F">8.结构类型系统</a>
                    <ul>
                        <li><a href="#t858.1%20%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%85%BC%E5%AE%B9%E6%80%A7">8.1
                                接口的兼容性</a></li>
                        <li><a
                                href="#t868.2%20%E5%9F%BA%E6%9C%AC%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%85%BC%E5%AE%B9%E6%80%A7">8.2
                                基本类型的兼容性</a></li>
                        <li><a href="#t878.3%20%E7%B1%BB%E7%9A%84%E5%85%BC%E5%AE%B9%E6%80%A7">8.3
                                类的兼容性</a></li>
                        <li><a href="#t888.4%20%E5%87%BD%E6%95%B0%E7%9A%84%E5%85%BC%E5%AE%B9%E6%80%A7">8.4
                                函数的兼容性</a>
                            <ul>
                                <li><a href="#t898.4.1%20%E6%AF%94%E8%BE%83%E5%8F%82%E6%95%B0">8.4.1
                                        比较参数</a></li>
                                <li><a href="#t908.4.2%20%E6%AF%94%E8%BE%83%E8%BF%94%E5%9B%9E%E5%80%BC">8.4.2
                                        比较返回值</a></li>
                            </ul>
                        </li>
                        <li><a
                                href="#t918.5%20%E5%87%BD%E6%95%B0%E7%9A%84%E5%8D%8F%E5%8F%98%E4%B8%8E%E9%80%86%E5%8F%98">8.5
                                函数的协变与逆变</a></li>
                        <li><a href="#t928.6%20%E6%B3%9B%E5%9E%8B%E7%9A%84%E5%85%BC%E5%AE%B9%E6%80%A7">8.6
                                泛型的兼容性</a></li>
                        <li><a href="#t938.7%20%E6%9E%9A%E4%B8%BE%E7%9A%84%E5%85%BC%E5%AE%B9%E6%80%A7">8.7
                                枚举的兼容性</a></li>
                    </ul>
                </li>
                <li><a href="#t949.%E7%B1%BB%E5%9E%8B%E4%BF%9D%E6%8A%A4">9.类型保护</a>
                    <ul>
                        <li><a href="#t959.1%20typeof%20%E7%B1%BB%E5%9E%8B%E4%BF%9D%E6%8A%A4">9.1
                                typeof 类型保护</a></li>
                        <li><a href="#t969.2%20instanceof%E7%B1%BB%E5%9E%8B%E4%BF%9D%E6%8A%A4">9.2
                                instanceof类型保护</a></li>
                        <li><a href="#t979.3%20null%E4%BF%9D%E6%8A%A4">9.3
                                null保护</a></li>
                        <li><a href="#t989.4%20%E9%93%BE%E5%88%A4%E6%96%AD%E8%BF%90%E7%AE%97%E7%AC%A6">9.4
                                链判断运算符</a></li>
                        <li><a
                                href="#t999.5%20%E5%8F%AF%E8%BE%A8%E8%AF%86%E7%9A%84%E8%81%94%E5%90%88%E7%B1%BB%E5%9E%8B">9.5
                                可辨识的联合类型</a></li>
                        <li><a href="#t1009.6%20in%E6%93%8D%E4%BD%9C%E7%AC%A6">9.6
                                in操作符</a></li>
                        <li><a
                                href="#t1019.7%20%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%E7%B1%BB%E5%9E%8B%E4%BF%9D%E6%8A%A4">9.7
                                自定义的类型保护</a></li>
                        <li><a href="#t1029.8%20unknown">9.8
                                unknown</a>
                            <ul>
                                <li><a href="#t1039.8.1%20any%20%E7%B1%BB%E5%9E%8B">9.8.1
                                        any 类型</a></li>
                                <li><a href="#t1049.8.2%20unknown%20%E7%B1%BB%E5%9E%8B">9.8.2
                                        unknown 类型</a></li>
                                <li><a
                                        href="#t1059.8.3%20%E7%BC%A9%E5%B0%8F%20unknown%20%E7%B1%BB%E5%9E%8B%E8%8C%83%E5%9B%B4">9.8.3
                                        缩小 unknown 类型范围</a></li>
                            </ul>
                        </li>
                        <li><a href="#t1069.8.4%20%E8%81%94%E5%90%88%E7%B1%BB%E5%9E%8B%E4%B8%AD%E7%9A%84%20unknown%20%E7%B1%BB%E5%9E%8B"
                                class="">9.8.4 联合类型中的 unknown 类型</a></li>
                        <li><a href="#t1079.8.5%20%20%E4%BA%A4%E5%8F%89%E7%B1%BB%E5%9E%8B%E4%B8%AD%E7%9A%84%20unknown%20%E7%B1%BB%E5%9E%8B"
                                class="">9.8.5 交叉类型中的 unknown 类型</a></li>
                        <li><a href="#t1089.8.6%20never%E6%98%AFunknown%E7%9A%84%E5%AD%90%E7%B1%BB%E5%9E%8B"
                                class="">9.8.6 never是unknown的子类型</a></li>
                        <li><a href="#t1099.8.7%20keyof%20unknown%20%E7%AD%89%E4%BA%8Enever" class="">9.8.7 keyof
                                unknown 等于never</a></li>
                        <li><a href="#t1109.8.8%20%E5%8F%AA%E8%83%BD%E5%AF%B9unknown%E8%BF%9B%E8%A1%8C%E7%AD%89%E6%88%96%E4%B8%8D%E7%AD%89%E6%93%8D%E4%BD%9C%EF%BC%8C%E4%B8%8D%E8%83%BD%E8%BF%9B%E8%A1%8C%E5%85%B6%E5%AE%83%E6%93%8D%E4%BD%9C"
                                class="">9.8.8 只能对unknown进行等或不等操作，不能进行其它操作</a></li>
                        <li><a href="#t1119.8.9%20%E4%B8%8D%E8%83%BD%E5%81%9A%E4%BB%BB%E4%BD%95%E6%93%8D%E4%BD%9C">9.8.9
                                不能做任何操作</a></li>
                        <li><a href="#t1129.8.10%20%E6%98%A0%E5%B0%84%E5%B1%9E%E6%80%A7">9.8.10
                                映射属性</a></li>
                    </ul>
                </li>
                <li><a href="#t11310.%20%E7%B1%BB%E5%9E%8B%E5%8F%98%E6%8D%A2">10.
                        类型变换</a>
                    <ul>
                        <li><a href="#t11410.1%20%E7%B1%BB%E5%9E%8B%E6%8E%A8%E6%96%AD">10.1
                                类型推断</a>
                            <ul>
                                <li><a href="#t11510.1.1%20%E4%BB%8E%E5%8F%B3%E5%90%91%E5%B7%A6">10.1.1
                                        从右向左</a></li>
                                <li><a href="#t11610.1.2%20%E5%BA%95%E9%83%A8%E6%B5%81%E5%87%BA" class="">10.1.2
                                        底部流出</a></li>
                                <li><a href="#t11710.1.3%20%E4%BB%8E%E5%B7%A6%E5%90%91%E5%8F%B3">10.1.3
                                        从左向右</a></li>
                                <li><a href="#t11810.1.4%20%E7%BB%93%E6%9E%84%E5%8C%96">10.1.4
                                        结构化</a></li>
                                <li><a href="#t11910.1.5%20%E8%A7%A3%E6%9E%84">10.1.5
                                        解构</a></li>
                                <li><a href="#t12010.1.5%20DefaultProps" class="">10.1.5 DefaultProps</a></li>
                                <li><a
                                        href="#t12110.1.6%20%E5%B0%8F%E5%BF%83%E4%BD%BF%E7%94%A8%E8%BF%94%E5%9B%9E%E5%80%BC">10.1.6
                                        小心使用返回值</a></li>
                            </ul>
                        </li>
                        <li><a href="#t12210.1%20%E4%BA%A4%E5%8F%89%E7%B1%BB%E5%9E%8B">10.1
                                交叉类型</a></li>
                        <li><a href="#t12310.2%20typeof">10.2
                                typeof</a></li>
                        <li><a href="#t12410.3%20%E7%B4%A2%E5%BC%95%E8%AE%BF%E9%97%AE%E6%93%8D%E4%BD%9C%E7%AC%A6">10.3
                                索引访问操作符</a></li>
                        <li><a href="#t12510.4%20keyof">10.4
                                keyof</a></li>
                        <li><a href="#t12610.5%20%E6%98%A0%E5%B0%84%E7%B1%BB%E5%9E%8B">10.5
                                映射类型</a></li>
                        <li><a href="#t12710.6%20%E6%9D%A1%E4%BB%B6%E7%B1%BB%E5%9E%8B">10.6
                                条件类型</a>
                            <ul>
                                <li><a href="#t12810.6.1%20%E5%AE%9A%E4%B9%89%E6%9D%A1%E4%BB%B6%E7%B1%BB%E5%9E%8B">10.6.1
                                        定义条件类型</a></li>
                                <li><a
                                        href="#t12910.6.2%20%E6%9D%A1%E4%BB%B6%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%88%86%E5%8F%91">10.6.2
                                        条件类型的分发</a></li>
                                <li><a href="#t13010.6.3%20%E5%86%85%E7%BD%AE%E6%9D%A1%E4%BB%B6%E7%B1%BB%E5%9E%8B">10.6.3
                                        内置条件类型</a>
                                    <ul>
                                        <li><a href="#t13110.6.3.1%20Exclude%3CT,%20U%3E">10.6.3.1
                                                Exclude<t, u=""></t,></a></li>
                                        <li><a href="#t13210.6.3.2%20Extract%3CT,%20U%3E">10.6.3.2
                                                Extract<t, u=""></t,></a></li>
                                        <li><a href="#t13310.6.3.3%20NonNullable">10.6.3.3
                                                NonNullable</a></li>
                                        <li><a href="#t13410.6.3.4%20ReturnType">10.6.3.4
                                                ReturnType</a></li>
                                        <li><a href="#t13510.6.3.5%20Parameters">10.6.3.5
                                                Parameters</a></li>
                                        <li><a href="#t13610.6.3.6%20InstanceType">10.6.3.6
                                                InstanceType</a></li>
                                        <li><a href="#t13710.6.3.7%20infer+%E5%88%86%E5%B8%83%E5%BC%8F">10.6.3.7
                                                infer+分布式</a></li>
                                    </ul>
                                </li>
                            </ul>
                        </li>
                        <li><a href="#t13810.7%20%E5%86%85%E7%BD%AE%E5%B7%A5%E5%85%B7%E7%B1%BB%E5%9E%8B">10.7
                                内置工具类型</a>
                            <ul>
                                <li><a href="#t13910.7.1%20Partial">10.7.1
                                        Partial</a></li>
                                <li><a href="#t14010.7.2%20%E7%B1%BB%E5%9E%8B%E9%80%92%E5%BD%92">10.7.2
                                        类型递归</a></li>
                                <li><a href="#t14110.7.3%20Required">10.7.3
                                        Required</a></li>
                                <li><a href="#t14210.7.4%20Readonly">10.7.4
                                        Readonly</a></li>
                                <li><a href="#t14310.7.5%20Pick">10.7.5
                                        Pick</a></li>
                                <li><a href="#t14410.7.6%20Record">10.7.6
                                        Record</a></li>
                            </ul>
                        </li>
                        <li><a href="#t14510.8%20%E8%87%AA%E5%AE%9A%E4%B9%89%E9%AB%98%E7%BA%A7%E7%B1%BB%E5%9E%8B">10.8
                                自定义高级类型</a>
                            <ul>
                                <li><a href="#t14610.8.1%20Proxy">10.8.1
                                        Proxy</a></li>
                                <li><a href="#t14710.8.2%20SetDifference">10.8.2
                                        SetDifference</a></li>
                                <li><a href="#t14810.8.3%20Omit">10.8.3
                                        Omit</a></li>
                                <li><a href="#t14910.8.4%20Diff">10.8.4
                                        Diff</a></li>
                                <li><a href="#t15010.8.5%20Intersection">10.8.5
                                        Intersection</a></li>
                                <li><a href="#t15110.8.6%20Overwrite">10.8.6
                                        Overwrite</a></li>
                                <li><a href="#t15210.8.7%20Merge">10.8.7
                                        Merge</a></li>
                                <li><a href="#t15310.8.8%20Mutable">10.8.8
                                        Mutable</a></li>
                            </ul>
                        </li>
                        <li><a href="#t15410.9%20%E9%9D%A2%E8%AF%95%E9%A2%98%E7%BB%BC%E5%90%88%E5%AE%9E%E6%88%98">10.9
                                面试题综合实战</a></li>
                    </ul>
                </li>
                <li><a href="#t15511.%20%E6%A8%A1%E5%9D%97VS%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4">11.
                        模块VS命名空间</a>
                    <ul>
                        <li><a href="#t15611.1%20%E6%A8%A1%E5%9D%97">11.1
                                模块</a>
                            <ul>
                                <li><a href="#t15711.1.1%20%E5%85%A8%E5%B1%80%E6%A8%A1%E5%9D%97">11.1.1
                                        全局模块</a></li>
                                <li><a href="#t15811.1.2%20%E6%96%87%E4%BB%B6%E6%A8%A1%E5%9D%97">11.1.2
                                        文件模块</a></li>
                                <li><a href="#t15911.1.3%20%E6%A8%A1%E5%9D%97%E8%A7%84%E8%8C%83">11.1.3
                                        模块规范</a></li>
                            </ul>
                        </li>
                        <li><a href="#t16011.2%20%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4">11.2
                                命名空间</a>
                            <ul>
                                <li><a href="#t16111.2.1%20%E5%86%85%E9%83%A8%E5%88%92%E5%88%86">11.2.1
                                        内部划分</a></li>
                                <li><a href="#t16211.2.2%20%E5%8E%9F%E7%90%86">11.2.2
                                        原理</a></li>
                            </ul>
                        </li>
                        <li><a
                                href="#t16311.3%20%E6%96%87%E4%BB%B6%EF%BC%8C%E6%A8%A1%E5%9D%97%E4%B8%8E%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4">11.3
                                文件，模块与命名空间</a>
                            <ul>
                                <li><a href="#t16411.3.1%20%E6%96%87%E4%BB%B6%E5%92%8C%E6%A8%A1%E5%9D%97">11.3.1
                                        文件和模块</a></li>
                                <li><a href="#t16511.3.2%20%E7%A9%BA%E9%97%B4">11.3.2
                                        空间</a></li>
                                <li><a href="#t16611.3.3%20%E6%96%87%E4%BB%B6">11.3.3
                                        文件</a></li>
                            </ul>
                        </li>
                    </ul>
                </li>
                <li><a href="#t16712.%E7%B1%BB%E5%9E%8B%E5%A3%B0%E6%98%8E">12.类型声明</a>
                    <ul>
                        <li><a href="#t16812.1%20%E6%99%AE%E9%80%9A%E7%B1%BB%E5%9E%8B%E5%A3%B0%E6%98%8E">12.1
                                普通类型声明</a></li>
                        <li><a href="#t16912.2%20%E5%A4%96%E9%83%A8%E6%9E%9A%E4%B8%BE">12.2
                                外部枚举</a></li>
                        <li><a href="#t17012.3%20namespace" class="my-active">12.3 namespace</a></li>
                        <li><a href="#t17112.4%20%E7%B1%BB%E5%9E%8B%E5%A3%B0%E6%98%8E%E6%96%87%E4%BB%B6" class="">12.4
                                类型声明文件</a>
                            <ul>
                                <li><a href="#t17212.4.1%20jquery.d.ts">12.4.1
                                        jquery.d.ts</a></li>
                                <li><a href="#t17312.4.2%20tsconfig.json">12.4.2
                                        tsconfig.json</a></li>
                                <li><a href="#t17412.4.3%20test.js">12.4.3
                                        test.js</a></li>
                            </ul>
                        </li>
                        <li><a href="#t17512.5%20%E7%AC%AC%E4%B8%89%E6%96%B9%E5%A3%B0%E6%98%8E%E6%96%87%E4%BB%B6"
                                class="">12.5 第三方声明文件</a>
                            <ul>
                                <li><a href="#t17612.5.1%20%E4%BD%BF%E7%94%A8jquery">12.5.1
                                        使用jquery</a></li>
                                <li><a href="#t17712.5.2%20%E5%AE%89%E8%A3%85%E5%A3%B0%E6%98%8E%E6%96%87%E4%BB%B6">12.5.2
                                        安装声明文件</a></li>
                                <li><a
                                        href="#t17812.5.3%20%E8%87%AA%E5%B7%B1%E7%BC%96%E5%86%99%E5%A3%B0%E6%98%8E%E6%96%87%E4%BB%B6">12.5.3
                                        自己编写声明文件</a>
                                    <ul>
                                        <li><a href="#t17912.5.3.1%20index.d.ts">12.5.3.1
                                                index.d.ts</a></li>
                                        <li><a href="#t18012.5.3.2%20tsconfig.json">12.5.3.2
                                                tsconfig.json</a></li>
                                    </ul>
                                </li>
                                <li><a
                                        href="#t18112.5.4%20npm%E5%A3%B0%E6%98%8E%E6%96%87%E4%BB%B6%E5%8F%AF%E8%83%BD%E7%9A%84%E4%BD%8D%E7%BD%AE">12.5.4
                                        npm声明文件可能的位置</a></li>
                                <li><a href="#t18212.5.5%20%E6%9F%A5%E6%89%BE%E5%A3%B0%E6%98%8E%E6%96%87%E4%BB%B6">12.5.5
                                        查找声明文件</a></li>
                            </ul>
                        </li>
                        <li><a
                                href="#t18312.6%20%E6%89%A9%E5%B1%95%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F%E7%9A%84%E7%B1%BB%E5%9E%8B">12.6
                                扩展全局变量的类型</a>
                            <ul>
                                <li><a
                                        href="#t18412.6.1%20%E6%89%A9%E5%B1%95%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F%E7%B1%BB%E5%9E%8B">12.6.1
                                        扩展局部变量类型</a></li>
                                <li><a
                                        href="#t18512.6.2%20%E6%A8%A1%E5%9D%97%E5%86%85%E5%85%A8%E5%B1%80%E6%89%A9%E5%B1%95">12.6.2
                                        模块内全局扩展</a></li>
                            </ul>
                        </li>
                        <li><a href="#t18612.7%20%E5%90%88%E5%B9%B6%E5%A3%B0%E6%98%8E">12.7
                                合并声明</a>
                            <ul>
                                <li><a href="#t18712.7.1%20%E5%90%88%E5%B9%B6%E7%B1%BB%E5%9E%8B%E5%A3%B0%E6%98%8E">12.7.1
                                        合并类型声明</a></li>
                                <li><a
                                        href="#t18812.7.2%20%E4%BD%BF%E7%94%A8%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4%E6%89%A9%E5%B1%95%E7%B1%BB">12.7.2
                                        使用命名空间扩展类</a></li>
                                <li><a
                                        href="#t18912.7.3%20%E4%BD%BF%E7%94%A8%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4%E6%89%A9%E5%B1%95%E5%87%BD%E6%95%B0">12.7.3
                                        使用命名空间扩展函数</a></li>
                                <li><a
                                        href="#t19012.7.4%20%E4%BD%BF%E7%94%A8%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4%E6%89%A9%E5%B1%95%E6%9E%9A%E4%B8%BE%E7%B1%BB%E5%9E%8B">12.7.4
                                        使用命名空间扩展枚举类型</a></li>
                                <li><a href="#t19112.7.5%20%E6%89%A9%E5%B1%95Store">12.7.5
                                        扩展Store</a></li>
                            </ul>
                        </li>
                        <li><a href="#t19212.8%20%E7%94%9F%E6%88%90%E5%A3%B0%E6%98%8E%E6%96%87%E4%BB%B6">12.8
                                生成声明文件</a></li>
                        <li><a href="#t19312.9%20%E7%B1%BB%E5%9E%8B%E5%A3%B0%E6%98%8E%E5%AE%9E%E6%88%98">12.9
                                类型声明实战</a>
                            <ul>
                                <li><a href="#t19412.9.1%20index.js">12.9.1
                                        index.js</a></li>
                                <li><a href="#t19512.9.2%20index.d.ts">12.9.2
                                        index.d.ts</a></li>
                            </ul>
                        </li>
                    </ul>
                </li>
            </ul>
        </div>
        <div class="content markdown-body">
            <h2 id="t01. typescript是什么">1. typescript是什么 <a href="#t01.%20typescript%E6%98%AF%E4%BB%80%E4%B9%88">
                    # </a></h2>
            <ul>
                <li>Typescript是由微软开发的一款开源的编程语言</li>
                <li>Typescript是Javascript的超集，遵循最新的ES5/ES6规范。TypeScript扩展了Javascript语法</li>
                <li>TypeScript更像后端Java、C#这样的面向对象语言可以让JS开发大型企业应用</li>
                <li>越来越多的项目是基于TS的，比如VSCode、Angular6、Vue3、React16</li>
                <li>TS提供的类型系统可以帮助我们在写代码的时候提供更丰富的语法提示</li>
                <li>在创建前的编译阶段经过类型系统的检查，就可以避免很多线上的错误</li>
            </ul>
            <p><img src="./typescript6/typescript.jpg" alt="typescript"></p>
            <h2 id="t12. TypeScript安装和编译">2. TypeScript安装和编译 <a
                    href="#t12.%20TypeScript%E5%AE%89%E8%A3%85%E5%92%8C%E7%BC%96%E8%AF%91">
                    # </a></h2>
            <h3 id="t22.1 安装">2.1 安装 <a href="#t22.1%20%E5%AE%89%E8%A3%85"> #
                </a></h3>
            <pre><code class="lang-js">cnpm i typescript -g
</code></pre>
            <pre><code class="lang-js">tsc helloworld.ts
</code></pre>
            <h3 id="t32.2 Vscode+TypeScript">2.2 Vscode+TypeScript <a href="#t32.2%20Vscode+TypeScript"> #
                </a></h3>
            <h4 id="t42.2.1  生成配置文件">2.2.1 生成配置文件 <a
                    href="#t42.2.1%20%20%E7%94%9F%E6%88%90%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6">
                    # </a></h4>
            <pre><code class="lang-js">tsc --init
</code></pre>
            <pre><code class="lang-json">{
  <span class="hljs-attr">"compilerOptions"</span>: {
    <span class="hljs-comment">/* Basic Options */</span>
    <span class="hljs-attr">"target"</span>: <span class="hljs-string">"es5"</span>,                          <span class="hljs-comment">/* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. 指定ECMAScript的目标版本*/</span>
    <span class="hljs-attr">"module"</span>: <span class="hljs-string">"commonjs"</span>,                     <span class="hljs-comment">/* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. 指定模块代码的生成方式*/</span>
    <span class="hljs-comment">// "lib": [],                             /* Specify library files to be included in the compilation. 指定编译的时候用来包含的编译文件*/</span>
    <span class="hljs-comment">// "allowJs": true,                       /* Allow javascript files to be compiled. 允许编译JS文件*/</span>
    <span class="hljs-comment">// "checkJs": true,                       /* Report errors in .js files. 在JS中包括错误*/</span>
    <span class="hljs-comment">// "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. 指定JSX代码的生成方式 是保留还是react-native或者react*/</span>
    <span class="hljs-comment">// "declaration": true,                   /* Generates corresponding '.d.ts' file.生成相应的类型声明文件 */</span>
    <span class="hljs-comment">// "declarationMap": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. 为每个类型声明文件生成相应的sourcemap*/</span>
    <span class="hljs-comment">// "sourceMap": true,                     /* Generates corresponding '.map' file. 生成对应的map文件 */</span>
    <span class="hljs-comment">// "outFile": "./",                       /* Concatenate and emit output to single file. 合并并且把编译后的内容输出 到一个文件里*/</span>
    <span class="hljs-comment">// "outDir": "./",                        /* Redirect output structure to the directory.按原始结构输出到目标目录 */</span>
    <span class="hljs-comment">// "rootDir": "./",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. 指定输入文件的根目录，用--outDir来控制输出的目录结构*/</span>
    <span class="hljs-comment">// "composite": true,                     /* Enable project compilation 启用项目编译*/</span>
    <span class="hljs-comment">// "removeComments": true,                /* Do not emit comments to output. 移除注释*/</span>
    <span class="hljs-comment">// "noEmit": true,                        /* Do not emit outputs. 不要输出*/</span>
    <span class="hljs-comment">// "importHelpers": true,                 /* Import emit helpers from 'tslib'. */</span>
    <span class="hljs-comment">// "downlevelIteration": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. 当目标是ES5或ES3的时候提供对for-of、扩展运算符和解构赋值中对于迭代器的完整支持*/</span>
    <span class="hljs-comment">// "isolatedModules": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule').r把每一个文件转译成一个单独的模块 */</span>

    <span class="hljs-comment">/* Strict Type-Checking Options */</span>
    <span class="hljs-comment">//"strict": true,                           /* Enable all strict type-checking options. 启用完全的严格类型检查 */</span>
    <span class="hljs-comment">// "noImplicitAny": true,                 /* Raise error on expressions and declarations with an implied 'any' type. 不能使用隐式的any类型*/</span>
    <span class="hljs-comment">// "strictNullChecks": true,              /* Enable strict null checks. 启用严格的NULL检查*/</span>
    <span class="hljs-comment">// "strictFunctionTypes": true,           /* Enable strict checking of function types. 启用严格的函数类型检查*/</span>
    <span class="hljs-comment">// "strictBindCallApply": true,           /* Enable strict 'bind', 'call', and 'apply' methods on functions.启用函数上严格的bind call 和apply方法 */</span>
    <span class="hljs-comment">// "strictPropertyInitialization": true,  /* Enable strict checking of property initialization in classes. 启用类上初始化属性检查*/</span>
    <span class="hljs-comment">// "noImplicitThis": true,                /* Raise error on 'this' expressions with an implied 'any' type.在默认的any中调用 this表达式报错 */</span>
    <span class="hljs-comment">// "alwaysStrict": true,                  /* Parse in strict mode and emit "use strict" for each source file. 在严格模式下解析并且向每个源文件中发射use strict*/</span>

    <span class="hljs-comment">/* Additional Checks */</span>
    <span class="hljs-comment">// "noUnusedLocals": true,                /* Report errors on unused locals. 有未使用到的本地变量时报错 */</span>
    <span class="hljs-comment">// "noUnusedParameters": true,            /* Report errors on unused parameters. 有未使用到的参数时报错*/</span>
    <span class="hljs-comment">// "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. 当不是所有的代码路径都有返回值的时候报错*/</span>
    <span class="hljs-comment">// "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. 在switch表达式中没有替代的case会报错 */</span>

    <span class="hljs-comment">/* Module Resolution Options */</span>
    <span class="hljs-comment">// "moduleResolution": "node",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). 指定模块的解析策略 node classic*/</span>
    <span class="hljs-comment">// "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. 在解析非绝对路径模块名的时候的基准路径*/</span>
    <span class="hljs-comment">// "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. 一些路径的集合*/</span>
    <span class="hljs-comment">// "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. 根目录的列表，在运行时用来合并内容*/</span>
    <span class="hljs-comment">// "typeRoots": [],                       /* List of folders to include type definitions from. 用来包含类型声明的文件夹列表*/</span>
    <span class="hljs-comment">// "types": [],                           /* Type declaration files to be included in compilation.在编译的时候被包含的类型声明 */</span>
    <span class="hljs-comment">// "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking.当没有默认导出的时候允许默认导入，这个在代码执行的时候没有作用，只是在类型检查的时候生效 */</span>
    <span class="hljs-comment">//"esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'.*/</span>
    <span class="hljs-comment">// "preserveSymlinks": true,              /* Do not resolve the real path of symlinks.不要symlinks解析的真正路径 */</span>

    <span class="hljs-comment">/* Source Map Options */</span>
    <span class="hljs-comment">// "sourceRoot": "",                      /* Specify the location where debugger should locate TypeScript files instead of source locations. 指定ts文件位置*/</span>
    <span class="hljs-comment">// "mapRoot": "",                         /* Specify the location where debugger should locate map files instead of generated locations. 指定 map文件存放的位置 */</span>
    <span class="hljs-comment">// "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. 源文件和sourcemap 文件在同一文件中，而不是把map文件放在一个单独的文件里*/</span>
    <span class="hljs-comment">// "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. 源文件和sourcemap 文件在同一文件中*/</span>

    <span class="hljs-comment">/* Experimental Options */</span>
    <span class="hljs-comment">// "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. 启动装饰器*/</span>
    <span class="hljs-comment">// "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */</span>
  }
}
</code></pre>
            <h4 id="t52.2.2 执行编译">2.2.2 执行编译 <a href="#t52.2.2%20%E6%89%A7%E8%A1%8C%E7%BC%96%E8%AF%91">
                    # </a></h4>
            <pre><code class="lang-js">tsc 
</code></pre>
            <h4 id="t62.2.3 vscode运行">2.2.3 vscode运行 <a href="#t62.2.3%20vscode%E8%BF%90%E8%A1%8C">
                    # </a></h4>
            <ul>
                <li>Terminal-&gt;Run Task-&gt; tsc:build 编译</li>
                <li>Terminal-&gt;Run Task-&gt; tsc:watch 编译并监听 </li>
            </ul>
            <h4 id="t72.2.4 npm scripts">2.2.4 npm scripts <a href="#t72.2.4%20npm%20scripts"> # </a>
            </h4>
            <ul>
                <li>npm run 实际上是调用本地的 Shell 来执行对应的 script value，所以理论上能兼容所有 bash 命令</li>
                <li>Shell 在类 Unix 系统上是 /bin/sh，在 Windows 上是 cmd.exe</li>
            </ul>
            <h4 id="t82.2.5 npm scripts 的 PATH">2.2.5 npm scripts 的 PATH <a
                    href="#t82.2.5%20npm%20scripts%20%E7%9A%84%20PATH">
                    # </a></h4>
            <ul>
                <li>npm run 会预置 PATH，对应包下的 node_modules/.bin 目录</li>
            </ul>
            <h2 id="t93. 数据类型">3. 数据类型 <a href="#t93.%20%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B">
                    # </a></h2>
            <h3 id="t103.1 布尔类型(boolean)">3.1 布尔类型(boolean) <a
                    href="#t103.1%20%E5%B8%83%E5%B0%94%E7%B1%BB%E5%9E%8B(boolean)">
                    # </a></h3>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> married: boolean=<span class="hljs-literal">false</span>;
</code></pre>
            <h3 id="t113.2 数字类型(number)">3.2 数字类型(number) <a
                    href="#t113.2%20%E6%95%B0%E5%AD%97%E7%B1%BB%E5%9E%8B(number)">
                    # </a></h3>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> age: number=<span class="hljs-number">10</span>;
</code></pre>
            <h3 id="t123.3 字符串类型(string)">3.3 字符串类型(string) <a
                    href="#t123.3%20%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%B1%BB%E5%9E%8B(string)">
                    # </a></h3>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> firstname: string=<span class="hljs-string">'zfpx'</span>;
</code></pre>
            <h3 id="t133.4 数组类型(array)">3.4 数组类型(array) <a href="#t133.4%20%E6%95%B0%E7%BB%84%E7%B1%BB%E5%9E%8B(array)">
                    # </a></h3>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> arr2: number[]=[<span class="hljs-number">4</span>,<span class="hljs-number">5</span>,<span class="hljs-number">6</span>];
<span class="hljs-keyword">let</span> arr3: <span class="hljs-built_in">Array</span>&lt;number&gt;=[<span class="hljs-number">7</span>,<span class="hljs-number">8</span>,<span class="hljs-number">9</span>];
</code></pre>
            <h3 id="t143.5 元组类型(tuple)">3.5 元组类型(tuple) <a href="#t143.5%20%E5%85%83%E7%BB%84%E7%B1%BB%E5%9E%8B(tuple)">
                    # </a></h3>
            <ul>
                <li>在 TypeScript 的基础类型中，元组（ Tuple ）表示一个已知<code>数量</code>和<code>类型</code>的数组</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> zhufeng:[string,number] = [<span class="hljs-string">'zhufeng'</span>,<span class="hljs-number">5</span>];
zhufeng[<span class="hljs-number">0</span>].length;
zhufeng[<span class="hljs-number">1</span>].toFixed(<span class="hljs-number">2</span>);
</code></pre>
            <table>
                <thead>
                    <tr>
                        <th style="text-align:left">元组</th>
                        <th style="text-align:left">数组</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td style="text-align:left">每一项可以是不同的类型</td>
                        <td style="text-align:left">每一项都是同一种类型</td>
                    </tr>
                    <tr>
                        <td style="text-align:left">有预定义的长度</td>
                        <td style="text-align:left">没有长度限制</td>
                    </tr>
                    <tr>
                        <td style="text-align:left">用于表示一个固定的结构</td>
                        <td style="text-align:left">用于表示一个列表</td>
                    </tr>
                </tbody>
            </table>
            <pre><code class="lang-js"><span class="hljs-keyword">const</span> animal:[string,number,boolean] = [<span class="hljs-string">'zhufeng'</span>,<span class="hljs-number">10</span>,<span class="hljs-literal">true</span>];
</code></pre>
            <h3 id="t153.6 枚举类型(enum)">3.6 枚举类型(enum) <a href="#t153.6%20%E6%9E%9A%E4%B8%BE%E7%B1%BB%E5%9E%8B(enum)">
                    # </a></h3>
            <ul>
                <li>事先考虑某一个变量的所有的可能的值，尽量用自然语言中的单词表示它的每一个值</li>
                <li>比如性别、月份、星期、颜色、单位、学历</li>
            </ul>
            <h4 id="t163.6.1 普通枚举">3.6.1 普通枚举 <a href="#t163.6.1%20%E6%99%AE%E9%80%9A%E6%9E%9A%E4%B8%BE">
                    # </a></h4>
            <pre><code class="lang-js">enum Gender{
    GIRL,
    BOY
}
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`李雷是<span class="hljs-subst">${Gender.BOY}</span>`</span>);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`韩梅梅是<span class="hljs-subst">${Gender.GIRL}</span>`</span>);

enum Week{
    MONDAY=<span class="hljs-number">1</span>,
    TUESDAY=<span class="hljs-number">2</span>
}
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`今天是星期<span class="hljs-subst">${Week.MONDAY}</span>`</span>);
</code></pre>
            <h4 id="t173.6.2 常数枚举">3.6.2 常数枚举 <a href="#t173.6.2%20%E5%B8%B8%E6%95%B0%E6%9E%9A%E4%B8%BE">
                    # </a></h4>
            <ul>
                <li>常数枚举与普通枚举的区别是，它会在编译阶段被删除，并且不能包含计算成员。</li>
                <li>假如包含了计算成员，则会在编译阶段报错</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">const</span> enum Colors {
    Red,
    Yellow,
    Blue
}

<span class="hljs-keyword">let</span> myColors = [Colors.Red, Colors.Yellow, Colors.Blue];
</code></pre>
            <pre><code class="lang-js"><span class="hljs-keyword">const</span> enum Color {Red, Yellow, Blue = <span class="hljs-string">"blue"</span>.length};
</code></pre>
            <h3 id="t183.7 任意类型(any)">3.7 任意类型(any) <a href="#t183.7%20%E4%BB%BB%E6%84%8F%E7%B1%BB%E5%9E%8B(any)">
                    # </a></h3>
            <ul>
                <li><code>any</code>就是可以赋值给任意类型</li>
                <li>第三方库没有提供类型文件时可以使用<code>any</code></li>
                <li>类型转换遇到困难时</li>
                <li>数据结构太复杂难以定义</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> root:any=<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>);
root.style.color=<span class="hljs-string">'red'</span>;
</code></pre>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> root:(HTMLElement|<span class="hljs-literal">null</span>)=<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>);
root!.style.color=<span class="hljs-string">'red'</span>;<span class="hljs-comment">//非空断言操作符</span>
</code></pre>
            <h3 id="t193.8 null 和 undefined">3.8 null 和 undefined <a href="#t193.8%20null%20%E5%92%8C%20undefined">
                    # </a></h3>
            <ul>
                <li>null 和 undefined 是其它类型的子类型，可以赋值给其它类型，如数字类型，此时，赋值后的类型会变成 null 或 undefined</li>
                <li><code>strictNullChecks</code> 参数用于新的严格空检查模式,在严格空检查模式下， null 和 undefined 值都不属于任何一个类型，它们只能赋值给自己这种类型或者
                    any</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> x: number;
x = <span class="hljs-number">1</span>;
x = <span class="hljs-literal">undefined</span>;    
x = <span class="hljs-literal">null</span>;   

<span class="hljs-keyword">let</span> y: number | <span class="hljs-literal">null</span> | <span class="hljs-literal">undefined</span>;
y = <span class="hljs-number">1</span>;
y = <span class="hljs-literal">undefined</span>;   
y = <span class="hljs-literal">null</span>;   
</code></pre>
            <h3 id="t203.9 void 类型">3.9 void 类型 <a href="#t203.9%20void%20%E7%B1%BB%E5%9E%8B">
                    # </a></h3>
            <ul>
                <li>void 表示没有任何类型</li>
                <li>当一个函数没有返回值时，TS 会认为它的返回值是 void 类型。</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">greeting</span>(<span class="hljs-params">name:string</span>):<span class="hljs-title">void</span> </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'hello'</span>,name);
    <span class="hljs-comment">//当我们声明一个变量类型是 void 的时候，它的非严格模式(strictNullChecks:false)下仅可以被赋值为 null 和 undefined</span>
    <span class="hljs-comment">//严格模式(strictNullChecks:true)下只能返回undefined</span>
    <span class="hljs-comment">//return null;</span>
    <span class="hljs-comment">//return undefined;</span>
}
</code></pre>
            <h3 id="t213.10 never类型">3.10 never类型 <a href="#t213.10%20never%E7%B1%BB%E5%9E%8B">
                    # </a></h3>
            <p>never是其它类型(null undefined)的子类型，代表不会出现的值</p>
            <h4 id="t223.10.1">3.10.1 <a href="#t223.10.1">
                    # </a></h4>
            <ul>
                <li>作为不会返回（ return ）的函数的返回值类型</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-comment">// 返回never的函数 必须存在 无法达到（ unreachable ） 的终点</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">error</span>(<span class="hljs-params">message: string</span>): <span class="hljs-title">never</span> </span>{
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(message);
}
<span class="hljs-keyword">let</span> result1 = error(<span class="hljs-string">'hello'</span>);
<span class="hljs-comment">// 由类型推论得到返回值为 never</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fail</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> error(<span class="hljs-string">"Something failed"</span>);
}
<span class="hljs-keyword">let</span> result = fail();

<span class="hljs-comment">// 返回never的函数 必须存在 无法达到（ unreachable ） 的终点</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">infiniteLoop</span>(<span class="hljs-params"></span>): <span class="hljs-title">never</span> </span>{
    <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {}
}
</code></pre>
            <h4 id="t233.10.2  strictNullChecks">3.10.2 strictNullChecks <a href="#t233.10.2%20%20strictNullChecks">
                    # </a></h4>
            <ul>
                <li>在 TS 中， null 和 undefined 是任何类型的有效值，所以无法正确地检测它们是否被错误地使用。于是 TS 引入了 --strictNullChecks 这一种检查模式</li>
                <li>由于引入了 --strictNullChecks ，在这一模式下，null 和 undefined 能被检测到。所以 TS 需要一种新的底部类型（ bottom type ）。所以就引入了
                    never。</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-comment">// Compiled with --strictNullChecks</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fn</span>(<span class="hljs-params">x: number | string</span>) </span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> x === <span class="hljs-string">'number'</span>) {
    <span class="hljs-comment">// x: number 类型</span>
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> x === <span class="hljs-string">'string'</span>) {
    <span class="hljs-comment">// x: string 类型</span>
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// x: never 类型</span>
    <span class="hljs-comment">// --strictNullChecks 模式下，这里的代码将不会被执行，x 无法被观察</span>
  }
}
</code></pre>
            <h4 id="t243.10.3  never 和 void 的区别">3.10.3 never 和 void 的区别 <a
                    href="#t243.10.3%20%20never%20%E5%92%8C%20void%20%E7%9A%84%E5%8C%BA%E5%88%AB">
                    # </a></h4>
            <ul>
                <li>void 可以被赋值为 null 和 undefined的类型。 never 则是一个不包含值的类型。</li>
                <li>拥有 void 返回值类型的函数能正常运行。拥有 never 返回值类型的函数无法正常返回，无法终止，或会抛出异常。</li>
            </ul>
            <h4 id="t253.11  Symbol">3.11 Symbol <a href="#t253.11%20%20Symbol"> # </a>
            </h4>
            <ul>
                <li>我们在使用 Symbol 的时候，必须添加 es6 的编译辅助库</li>
                <li>Symbol 是在ES2015之后成为新的原始类型,它通过 Symbol 构造函数创建</li>
                <li>Symbol 的值是唯一不变的</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">const</span> sym1 = <span class="hljs-built_in">Symbol</span>(<span class="hljs-string">'key'</span>);
<span class="hljs-keyword">const</span> sym2 = <span class="hljs-built_in">Symbol</span>(<span class="hljs-string">'key'</span>);
<span class="hljs-built_in">Symbol</span>(<span class="hljs-string">'key'</span>) === <span class="hljs-built_in">Symbol</span>(<span class="hljs-string">'key'</span>) <span class="hljs-comment">// false</span>
</code></pre>
            <h4 id="t263.12  BigInt">3.12 BigInt <a href="#t263.12%20%20BigInt"> # </a>
            </h4>
            <ul>
                <li>使用 BigInt 可以安全地存储和操作大整数</li>
                <li>我们在使用 <code>BigInt</code> 的时候，必须添加 <code>ESNext</code> 的编译辅助库</li>
                <li>要使用<code>1n</code>需要 <code>"target": "ESNext"</code></li>
                <li>number和 BigInt类型不一样,不兼容</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">const</span> max = <span class="hljs-built_in">Number</span>.MAX_SAFE_INTEGER;<span class="hljs-comment">// 2**53-1</span>
<span class="hljs-built_in">console</span>.log(max + <span class="hljs-number">1</span> === max + <span class="hljs-number">2</span>);
</code></pre>
            <pre><code class="lang-js"><span class="hljs-keyword">const</span> max = BigInt(<span class="hljs-built_in">Number</span>.MAX_SAFE_INTEGER);
<span class="hljs-built_in">console</span>.log(max + <span class="hljs-number">1n</span> === max + <span class="hljs-number">2n</span>);
</code></pre>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> foo: number;
<span class="hljs-keyword">let</span> bar: bigint;
foo =bar;
bar = foo;
</code></pre>
            <h3 id="t273.13 类型推论">3.13 类型推论 <a href="#t273.13%20%E7%B1%BB%E5%9E%8B%E6%8E%A8%E8%AE%BA">
                    # </a></h3>
            <ul>
                <li>是指编程语言中能够自动推导出值的类型的能力，它是一些强静态类型语言中出现的特性</li>
                <li>定义时未赋值就会推论成any类型</li>
                <li>如果定义的时候就赋值就能利用到类型推论</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> username2;
username2 = <span class="hljs-number">10</span>;
username2 = <span class="hljs-string">'zhufeng'</span>;
username2 = <span class="hljs-literal">null</span>;
</code></pre>
            <h3 id="t283.14  包装对象（Wrapper Object）">3.14 包装对象（Wrapper Object） <a
                    href="#t283.14%20%20%E5%8C%85%E8%A3%85%E5%AF%B9%E8%B1%A1%EF%BC%88Wrapper%20Object%EF%BC%89">
                    # </a></h3>
            <ul>
                <li>JavaScript 的类型分为两种：原始数据类型（Primitive data types）和对象类型（Object types）。</li>
                <li>所有的原始数据类型都没有属性（property）</li>
                <li>原始数据类型<ul>
                        <li>布尔值</li>
                        <li>数值</li>
                        <li>字符串</li>
                        <li>null</li>
                        <li>undefined </li>
                        <li>Symbol</li>
                    </ul>
                </li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> name = <span class="hljs-string">'zhufeng'</span>;
<span class="hljs-built_in">console</span>.log(name.toUpperCase());

<span class="hljs-built_in">console</span>.log((<span class="hljs-keyword">new</span> <span class="hljs-built_in">String</span>(<span class="hljs-string">'zhufeng'</span>)).toUpperCase());
</code></pre>
            <ul>
                <li>当调用基本数据类型方法的时候，JavaScript 会在原始数据类型和对象类型之间做一个迅速的强制性切换</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> isOK: boolean = <span class="hljs-literal">true</span>; <span class="hljs-comment">// 编译通过</span>
<span class="hljs-keyword">let</span> isOK: boolean = <span class="hljs-built_in">Boolean</span>(<span class="hljs-number">1</span>) <span class="hljs-comment">// 编译通过</span>
<span class="hljs-keyword">let</span> isOK: boolean = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Boolean</span>(<span class="hljs-number">1</span>); <span class="hljs-comment">// 编译失败   期望的 isOK 是一个原始数据类型</span>
</code></pre>
            <h3 id="t293.15 联合类型">3.15 联合类型 <a href="#t293.15%20%E8%81%94%E5%90%88%E7%B1%BB%E5%9E%8B">
                    # </a></h3>
            <ul>
                <li>联合类型（Union Types）表示取值可以为多种类型中的一种</li>
                <li>未赋值时联合类型上只能访问两个类型共有的属性和方法</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> name: string | number;
<span class="hljs-built_in">console</span>.log(name.toString());
name = <span class="hljs-number">3</span>;
<span class="hljs-built_in">console</span>.log(name.toFixed(<span class="hljs-number">2</span>));
name = <span class="hljs-string">'zhufeng'</span>;
<span class="hljs-built_in">console</span>.log(name.length);

<span class="hljs-keyword">export</span> {};
</code></pre>
            <h3 id="t303.16 类型断言">3.16 类型断言 <a href="#t303.16%20%E7%B1%BB%E5%9E%8B%E6%96%AD%E8%A8%80">
                    # </a></h3>
            <ul>
                <li>类型断言可以将一个联合类型的变量，指定为一个更加具体的类型</li>
                <li>不能将联合类型断言为不存在的类型</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> name: string | number;
<span class="hljs-built_in">console</span>.log((name <span class="hljs-keyword">as</span> string).length);
<span class="hljs-built_in">console</span>.log((name <span class="hljs-keyword">as</span> number).toFixed(<span class="hljs-number">2</span>));
<span class="hljs-built_in">console</span>.log((name <span class="hljs-keyword">as</span> boolean));
</code></pre>
            <p>双重断言</p>
            <pre><code class="lang-js">interface Person {
    <span class="hljs-attr">name</span>: string;
    age: number;
}
<span class="hljs-keyword">const</span> person = <span class="hljs-string">'zhufeng'</span> <span class="hljs-keyword">as</span> any <span class="hljs-keyword">as</span> Person; <span class="hljs-comment">// ok</span>
</code></pre>
            <h3 id="t313.17 字面量类型和类型字面量">3.17 字面量类型和类型字面量 <a
                    href="#t313.17%20%E5%AD%97%E9%9D%A2%E9%87%8F%E7%B1%BB%E5%9E%8B%E5%92%8C%E7%B1%BB%E5%9E%8B%E5%AD%97%E9%9D%A2%E9%87%8F">
                    # </a></h3>
            <ul>
                <li>字面量类型的要和实际的值的字面量一一对应,如果不一致就会报错</li>
                <li>类型字面量和对象字面量的语法很相似</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">const</span> up:<span class="hljs-string">'Up'</span>= <span class="hljs-string">'Up'</span>;
<span class="hljs-keyword">const</span> down: <span class="hljs-string">"Down"</span> = <span class="hljs-string">"Down"</span>;
<span class="hljs-keyword">const</span> left: <span class="hljs-string">"Left"</span> = <span class="hljs-string">"Left"</span>;
<span class="hljs-keyword">const</span> right: <span class="hljs-string">"Right"</span> = <span class="hljs-string">"Right"</span>;
type Direction = <span class="hljs-string">'Up'</span> | <span class="hljs-string">'Down'</span> | <span class="hljs-string">'Left'</span> | <span class="hljs-string">'Right'</span>;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">move</span>(<span class="hljs-params">direction: Direction</span>) </span>{}
move(<span class="hljs-string">"Up"</span>);
</code></pre>
            <pre><code class="lang-js">type Person = {
  <span class="hljs-attr">name</span>:string,
  <span class="hljs-attr">age</span>:number
};
</code></pre>
            <h3 id="t323.18 字符串字面量 vs 联合类型">3.18 字符串字面量 vs 联合类型 <a
                    href="#t323.18%20%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%AD%97%E9%9D%A2%E9%87%8F%20vs%20%E8%81%94%E5%90%88%E7%B1%BB%E5%9E%8B">
                    # </a></h3>
            <ul>
                <li>字符串字面量类型用来约束取值只能是某<code>几个字符串</code>中的一个, 联合类型（Union Types）表示取值可以为<code>多种类型</code>中的一种</li>
                <li>字符串字面量 限定了使用该字面量的地方仅接受特定的值,联合类型 对于值并没有限定，仅仅限定值的类型需要保持一致</li>
            </ul>
            <h2 id="t334. 函数">4. 函数 <a href="#t334.%20%E5%87%BD%E6%95%B0"> #
                </a></h2>
            <h3 id="t344.1 函数的定义">4.1 函数的定义 <a href="#t344.1%20%E5%87%BD%E6%95%B0%E7%9A%84%E5%AE%9A%E4%B9%89">
                    # </a></h3>
            <ul>
                <li>可以指定参数的类型和返回值的类型</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hello</span>(<span class="hljs-params">name:string</span>):<span class="hljs-title">void</span> </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'hello'</span>,name);
}
hello(<span class="hljs-string">'zfpx'</span>);
</code></pre>
            <h3 id="t354.2 函数表达式">4.2 函数表达式 <a href="#t354.2%20%E5%87%BD%E6%95%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F">
                    # </a></h3>
            <ul>
                <li>定义函数类型</li>
            </ul>
            <pre><code class="lang-js">type GetUsernameFunction = <span class="hljs-function">(<span class="hljs-params">x:string,y:string</span>)=&gt;</span>string;
<span class="hljs-keyword">let</span> getUsername:GetUsernameFunction = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">firstName,lastName</span>)</span>{
  <span class="hljs-keyword">return</span> firstName + lastName;
}
</code></pre>
            <h3 id="t364.3 没有返回值">4.3 没有返回值 <a href="#t364.3%20%E6%B2%A1%E6%9C%89%E8%BF%94%E5%9B%9E%E5%80%BC">
                    # </a></h3>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> hello2 = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">name:string</span>):<span class="hljs-title">void</span> </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'hello2'</span>,name);
    <span class="hljs-keyword">return</span> <span class="hljs-literal">undefined</span>;
}
hello2(<span class="hljs-string">'zhufeng'</span>);
</code></pre>
            <h3 id="t374.4 可选参数">4.4 可选参数 <a href="#t374.4%20%E5%8F%AF%E9%80%89%E5%8F%82%E6%95%B0">
                    # </a></h3>
            <p>在TS中函数的形参和实参必须一样，不一样就要配置可选参数,而且必须是最后一个参数</p>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">print</span>(<span class="hljs-params">name:string,age?:number</span>):<span class="hljs-title">void</span> </span>{
    <span class="hljs-built_in">console</span>.log(name,age);
}
print(<span class="hljs-string">'zfpx'</span>);
</code></pre>
            <h3 id="t384.5 默认参数">4.5 默认参数 <a href="#t384.5%20%E9%BB%98%E8%AE%A4%E5%8F%82%E6%95%B0">
                    # </a></h3>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ajax</span>(<span class="hljs-params">url:string,method:string=<span class="hljs-string">'GET'</span></span>) </span>{
    <span class="hljs-built_in">console</span>.log(url,method);
}
ajax(<span class="hljs-string">'/users'</span>);
</code></pre>
            <h3 id="t394.6 剩余参数">4.6 剩余参数 <a href="#t394.6%20%E5%89%A9%E4%BD%99%E5%8F%82%E6%95%B0">
                    # </a></h3>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sum</span>(<span class="hljs-params">...numbers:number[]</span>) </span>{
    <span class="hljs-keyword">return</span> numbers.reduce(<span class="hljs-function">(<span class="hljs-params">val,item</span>)=&gt;</span>val+=item,<span class="hljs-number">0</span>);
}
<span class="hljs-built_in">console</span>.log(sum(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>));
</code></pre>
            <h3 id="t404.7 函数重载">4.7 函数重载 <a href="#t404.7%20%E5%87%BD%E6%95%B0%E9%87%8D%E8%BD%BD">
                    # </a></h3>
            <ul>
                <li>在Java中的重载，指的是两个或者两个以上的同名函数，参数不一样</li>
                <li>在TypeScript中，表现为给同一个函数提供多个函数类型定义</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> obj: any={};
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">attr</span>(<span class="hljs-params">val: string</span>): <span class="hljs-title">void</span>;
<span class="hljs-title">function</span> <span class="hljs-title">attr</span>(<span class="hljs-params">val: number</span>): <span class="hljs-title">void</span>;
<span class="hljs-title">function</span> <span class="hljs-title">attr</span>(<span class="hljs-params">val:any</span>):<span class="hljs-title">void</span> </span>{
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> val === <span class="hljs-string">'string'</span>) {
        obj.name=val;
    } <span class="hljs-keyword">else</span> {
        obj.age=val;
    }
}
attr(<span class="hljs-string">'zfpx'</span>);
attr(<span class="hljs-number">9</span>);
attr(<span class="hljs-literal">true</span>);
<span class="hljs-built_in">console</span>.log(obj);
</code></pre>
            <h2 id="t415. 类">5. 类 <a href="#t415.%20%E7%B1%BB"> # </a></h2>
            <h3 id="t425.1 如何定义类">5.1 如何定义类 <a href="#t425.1%20%E5%A6%82%E4%BD%95%E5%AE%9A%E4%B9%89%E7%B1%BB">
                    # </a></h3>
            <ul>
                <li>"strictPropertyInitialization": true /<em> 启用类属性初始化的严格检查</em>/</li>
                <li>name!:string </li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span></span>{
    <span class="hljs-attr">name</span>:string;
    getName():<span class="hljs-keyword">void</span>{
        <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">this</span>.name);
    }
}
<span class="hljs-keyword">let</span> p1 = <span class="hljs-keyword">new</span> Person();
p1.name = <span class="hljs-string">'zhufeng'</span>;
p1.getName();
</code></pre>
            <pre><code class="lang-js"><span class="hljs-comment">/**
 * 当我们写一个类的时候,会得到2个类型
 * 1. 构造函数类型的函数类型
 * 2. 类的实例类型
 */</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Component</span> </span>{
    <span class="hljs-keyword">static</span> myName: string = <span class="hljs-string">'静态名称属性'</span>;
    myName: string = <span class="hljs-string">'实例名称属性'</span>;
}
<span class="hljs-keyword">let</span> com = Component;
<span class="hljs-comment">//Component类名本身表示的是实例的类型</span>
<span class="hljs-comment">//ts 一个类型 一个叫值 </span>
<span class="hljs-comment">//冒号后面的是类型</span>
<span class="hljs-comment">//放在=后面的是值</span>
<span class="hljs-keyword">let</span> c: Component = <span class="hljs-keyword">new</span> Component();
<span class="hljs-keyword">let</span> f: <span class="hljs-keyword">typeof</span> Component = com;
</code></pre>
            <h3 id="t435.2 存取器">5.2 存取器 <a href="#t435.2%20%E5%AD%98%E5%8F%96%E5%99%A8">
                    # </a></h3>
            <ul>
                <li>在 TypeScript 中，我们可以通过存取器来改变一个类中属性的读取和赋值行为</li>
                <li>构造函数<ul>
                        <li>主要用于初始化类的成员变量属性</li>
                        <li>类的对象创建时自动调用执行</li>
                        <li>没有返回值</li>
                    </ul>
                </li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>{
    <span class="hljs-attr">myname</span>:string;
    <span class="hljs-keyword">constructor</span>(myname: string) {
        <span class="hljs-keyword">this</span>.myname = myname;
    }
    <span class="hljs-keyword">get</span> name() {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.myname;
    }
    <span class="hljs-keyword">set</span> name(value) {
        <span class="hljs-keyword">this</span>.myname = value;
    }
}

<span class="hljs-keyword">let</span> user = <span class="hljs-keyword">new</span> User(<span class="hljs-string">'zhufeng'</span>);
user.name = <span class="hljs-string">'jiagou'</span>; 
<span class="hljs-built_in">console</span>.log(user.name); 
</code></pre>
            <pre><code class="lang-js"><span class="hljs-meta">"use strict"</span>;
<span class="hljs-keyword">var</span> User = <span class="hljs-comment">/** @class */</span> (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">User</span>(<span class="hljs-params">myname</span>) </span>{
        <span class="hljs-keyword">this</span>.myname = myname;
    }
    <span class="hljs-built_in">Object</span>.defineProperty(User.prototype, <span class="hljs-string">"name"</span>, {
        <span class="hljs-attr">get</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.myname;
        },
        <span class="hljs-attr">set</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">value</span>) </span>{
            <span class="hljs-keyword">this</span>.myname = value;
        },
        <span class="hljs-attr">enumerable</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">configurable</span>: <span class="hljs-literal">true</span>
    });
    <span class="hljs-keyword">return</span> User;
}());
<span class="hljs-keyword">var</span> user = <span class="hljs-keyword">new</span> User(<span class="hljs-string">'zhufeng'</span>);
user.name = <span class="hljs-string">'jiagou'</span>;
<span class="hljs-built_in">console</span>.log(user.name);
</code></pre>
            <h3 id="t445.3 参数属性">5.3 参数属性 <a href="#t445.3%20%E5%8F%82%E6%95%B0%E5%B1%9E%E6%80%A7">
                    # </a></h3>
            <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>{
    <span class="hljs-keyword">constructor</span>(public myname: string) {}
    <span class="hljs-keyword">get</span> name() {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.myname;
    }
    <span class="hljs-keyword">set</span> name(value) {
        <span class="hljs-keyword">this</span>.myname = value;
    }
}

<span class="hljs-keyword">let</span> user = <span class="hljs-keyword">new</span> User(<span class="hljs-string">'zhufeng'</span>);
<span class="hljs-built_in">console</span>.log(user.name); 
user.name = <span class="hljs-string">'jiagou'</span>; 
<span class="hljs-built_in">console</span>.log(user.name);
</code></pre>
            <h3 id="t455.4 readonly">5.4 readonly <a href="#t455.4%20readonly"> # </a></h3>
            <ul>
                <li>readonly修饰的变量只能在<code>构造函数</code>中初始化</li>
                <li>在 TypeScript 中，const 是<code>常量</code>标志符，其值不能被重新分配</li>
                <li>TypeScript 的类型系统同样也允许将 interface、type、 class 上的属性标识为 readonly</li>
                <li>readonly 实际上只是在<code>编译</code>阶段进行代码检查。而 const 则会在<code>运行时</code>检查（在支持 const 语法的 JavaScript
                    运行时环境中）</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span> </span>{
    public readonly name: string
    <span class="hljs-keyword">constructor</span>(name:string) {
        <span class="hljs-keyword">this</span>.name = name;
    }
    changeName(name:string){
        <span class="hljs-keyword">this</span>.name = name;
    }
}

<span class="hljs-keyword">let</span> a = <span class="hljs-keyword">new</span> Animal(<span class="hljs-string">'zhufeng'</span>);
a.changeName(<span class="hljs-string">'jiagou'</span>);
</code></pre>
            <h3 id="t465.5 继承">5.5 继承 <a href="#t465.5%20%E7%BB%A7%E6%89%BF"> #
                </a></h3>
            <ul>
                <li>子类继承父类后子类的实例就拥有了父类中的属性和方法，可以增强代码的可复用性</li>
                <li>将子类公用的方法抽象出来放在父类中，自己的特殊逻辑放在子类中重写父类的逻辑</li>
                <li>super可以调用父类上的方法和属性</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{
    <span class="hljs-attr">name</span>: string;<span class="hljs-comment">//定义实例的属性，默认省略public修饰符</span>
    age: number;
    <span class="hljs-keyword">constructor</span>(name:string,age:number) {<span class="hljs-comment">//构造函数</span>
        <span class="hljs-keyword">this</span>.name=name;
        <span class="hljs-keyword">this</span>.age=age;
    }
    getName():string {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.name;
    }
    setName(name:string): <span class="hljs-keyword">void</span>{
        <span class="hljs-keyword">this</span>.name=name;
    }
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Student</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Person</span></span>{
    <span class="hljs-attr">no</span>: number;
    <span class="hljs-keyword">constructor</span>(name:string,age:number,no:number) {
        <span class="hljs-keyword">super</span>(name,age);
        <span class="hljs-keyword">this</span>.no=no;
    }
    getNo():number {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.no;
    }
}
<span class="hljs-keyword">let</span> s1=<span class="hljs-keyword">new</span> Student(<span class="hljs-string">'zfpx'</span>,<span class="hljs-number">10</span>,<span class="hljs-number">1</span>);
<span class="hljs-built_in">console</span>.log(s1);

</code></pre>
            <h3 id="t475.6 类里面的修饰符">5.6 类里面的修饰符 <a
                    href="#t475.6%20%E7%B1%BB%E9%87%8C%E9%9D%A2%E7%9A%84%E4%BF%AE%E9%A5%B0%E7%AC%A6">
                    # </a></h3>
            <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Father</span> </span>{
    public name: string;  <span class="hljs-comment">//类里面 子类 其它任何地方外边都可以访问</span>
    protected age: number; <span class="hljs-comment">//类里面 子类 都可以访问,其它任何地方不能访问</span>
    private money: number; <span class="hljs-comment">//类里面可以访问， 子类和其它任何地方都不可以访问</span>
    <span class="hljs-keyword">constructor</span>(name:string,age:number,money:number) {<span class="hljs-comment">//构造函数</span>
        <span class="hljs-keyword">this</span>.name=name;
        <span class="hljs-keyword">this</span>.age=age;
        <span class="hljs-keyword">this</span>.money=money;
    }
    getName():string {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.name;
    }
    setName(name:string): <span class="hljs-keyword">void</span>{
        <span class="hljs-keyword">this</span>.name=name;
    }
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Child</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Father</span></span>{
    <span class="hljs-keyword">constructor</span>(name:string,age:number,money:number) {
        <span class="hljs-keyword">super</span>(name,age,money);
    }
    desc() {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-keyword">this</span>.name}</span> <span class="hljs-subst">${<span class="hljs-keyword">this</span>.age}</span> <span class="hljs-subst">${<span class="hljs-keyword">this</span>.money}</span>`</span>);
    }
}

<span class="hljs-keyword">let</span> child = <span class="hljs-keyword">new</span> Child(<span class="hljs-string">'zfpx'</span>,<span class="hljs-number">10</span>,<span class="hljs-number">1000</span>);
<span class="hljs-built_in">console</span>.log(child.name);
<span class="hljs-built_in">console</span>.log(child.age);
<span class="hljs-built_in">console</span>.log(child.money);
</code></pre>
            <h3 id="t485.7 静态属性 静态方法">5.7 静态属性 静态方法 <a
                    href="#t485.7%20%E9%9D%99%E6%80%81%E5%B1%9E%E6%80%A7%20%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95">
                    # </a></h3>
            <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Father</span> </span>{
    <span class="hljs-keyword">static</span> className=<span class="hljs-string">'Father'</span>;
    <span class="hljs-keyword">static</span> getClassName() {
        <span class="hljs-keyword">return</span> Father.className;
    }
    public name: string;
    <span class="hljs-keyword">constructor</span>(name:string) {<span class="hljs-comment">//构造函数</span>
        <span class="hljs-keyword">this</span>.name=name;
    }

}
<span class="hljs-built_in">console</span>.log(Father.className);
<span class="hljs-built_in">console</span>.log(Father.getClassName());
</code></pre>
            <h3 id="t495.8 装饰器">5.8 装饰器 <a href="#t495.8%20%E8%A3%85%E9%A5%B0%E5%99%A8">
                    # </a></h3>
            <ul>
                <li>装饰器是一种特殊类型的声明，它能够被附加到类声明、方法、属性或参数上，可以修改类的行为</li>
                <li>常见的装饰器有类装饰器、属性装饰器、方法装饰器和参数装饰器</li>
                <li>装饰器的写法分为普通装饰器和装饰器工厂</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span></span>{
    say() {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'hello'</span>)
    }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Person</span>(<span class="hljs-params"></span>) </span>{}
<span class="hljs-built_in">Object</span>.defineProperty(Person.prototype, <span class="hljs-string">'say'</span>, {
    <span class="hljs-attr">value</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'hello'</span>); },
    <span class="hljs-attr">enumerable</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">configurable</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">writable</span>: <span class="hljs-literal">true</span>
});
</code></pre>
            <h4 id="t505.8.1 类装饰器">5.8.1 类装饰器 <a href="#t505.8.1%20%E7%B1%BB%E8%A3%85%E9%A5%B0%E5%99%A8">
                    # </a></h4>
            <ul>
                <li>类装饰器在类声明之前声明，用来监视、修改或替换类定义</li>
            </ul>
            <pre><code class="lang-js">namespace a {
    <span class="hljs-comment">//当装饰器作为修饰类的时候，会把构造器传递进去</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addNameEat</span>(<span class="hljs-params">constructor: Function</span>) </span>{
      <span class="hljs-keyword">constructor</span>.prototype.name = "zhufeng";
      <span class="hljs-keyword">constructor</span>.prototype.eat = function () {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"eat"</span>);
      };
    }
    @addNameEat
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{
      name!: string;
      eat!: <span class="hljs-built_in">Function</span>;
      <span class="hljs-keyword">constructor</span>() {}
    }
    <span class="hljs-keyword">let</span> p: Person = <span class="hljs-keyword">new</span> Person();
    <span class="hljs-built_in">console</span>.log(p.name);
    p.eat();
}

namespace b {
    <span class="hljs-comment">//还可以使用装饰器工厂</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addNameEatFactory</span>(<span class="hljs-params">name:string</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">constructor: Function</span>) </span>{
        <span class="hljs-keyword">constructor</span>.prototype.name = name;
        <span class="hljs-keyword">constructor</span>.prototype.eat = function () {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"eat"</span>);
        };
    };
    }
    @addNameEatFactory(<span class="hljs-string">'zhufeng'</span>)
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{
      name!: string;
      eat!: <span class="hljs-built_in">Function</span>;
      <span class="hljs-keyword">constructor</span>() {}}
    <span class="hljs-keyword">let</span> p: Person = <span class="hljs-keyword">new</span> Person();
    <span class="hljs-built_in">console</span>.log(p.name);
    p.eat();
}

namespace c {
    <span class="hljs-comment">//还可以替换类,不过替换的类要与原类结构相同</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">enhancer</span>(<span class="hljs-params">constructor: Function</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-class"><span class="hljs-keyword">class</span> </span>{
        <span class="hljs-attr">name</span>: string = <span class="hljs-string">"jiagou"</span>;
        eat() {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"吃饭饭"</span>);
        }
    };
    }
    @enhancer
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{
      name!: string;
      eat!: <span class="hljs-built_in">Function</span>;
      <span class="hljs-keyword">constructor</span>() {}}
    <span class="hljs-keyword">let</span> p: Person = <span class="hljs-keyword">new</span> Person();
    <span class="hljs-built_in">console</span>.log(p.name);
    p.eat();

}
</code></pre>
            <h4 id="t515.8.2 属性装饰器">5.8.2 属性装饰器 <a href="#t515.8.2%20%E5%B1%9E%E6%80%A7%E8%A3%85%E9%A5%B0%E5%99%A8">
                    # </a></h4>
            <ul>
                <li>属性装饰器表达式会在运行时当作函数被调用，传入下列2个参数</li>
                <li>属性装饰器用来装饰属性<ul>
                        <li>第一个参数对于静态成员来说是类的构造函数，对于实例成员是类的原型对象</li>
                        <li>第二个参数是属性的名称</li>
                    </ul>
                </li>
                <li>方法装饰器用来装饰方法<ul>
                        <li>第一个参数对于静态成员来说是类的构造函数，对于实例成员是类的原型对象</li>
                        <li>第二个参数是方法的名称</li>
                        <li>第三个参数是方法描述符</li>
                    </ul>
                </li>
            </ul>
            <pre><code class="lang-js">namespace d {
    <span class="hljs-comment">//修饰实例属性</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">upperCase</span>(<span class="hljs-params">target: any, propertyKey: string</span>) </span>{
        <span class="hljs-keyword">let</span> value = target[propertyKey];
        <span class="hljs-keyword">const</span> getter = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            <span class="hljs-keyword">return</span> value;
        }
        <span class="hljs-comment">// 用来替换的setter</span>
        <span class="hljs-keyword">const</span> setter = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">newVal: string</span>) </span>{
            value = newVal.toUpperCase()
        };
        <span class="hljs-comment">// 替换属性，先删除原先的属性，再重新定义属性</span>
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">delete</span> target[propertyKey]) {
            <span class="hljs-built_in">Object</span>.defineProperty(target, propertyKey, {
                <span class="hljs-attr">get</span>: getter,
                <span class="hljs-attr">set</span>: setter,
                <span class="hljs-attr">enumerable</span>: <span class="hljs-literal">true</span>,
                <span class="hljs-attr">configurable</span>: <span class="hljs-literal">true</span>
            });
        }
    }
    <span class="hljs-comment">//修饰实例方法</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">noEnumerable</span>(<span class="hljs-params">target: any, property: string, descriptor: PropertyDescriptor</span>) </span>{
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'target.getName'</span>, target.getName);
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'target.getAge'</span>, target.getAge);
        descriptor.enumerable = <span class="hljs-literal">true</span>;
    }
    <span class="hljs-comment">//重写方法</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toNumber</span>(<span class="hljs-params">target: any, methodName: string, descriptor: PropertyDescriptor</span>) </span>{
        <span class="hljs-keyword">let</span> oldMethod = descriptor.value;
        descriptor.value = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">...args: any[]</span>) </span>{
            args = args.map(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> <span class="hljs-built_in">parseFloat</span>(item));
            <span class="hljs-keyword">return</span> oldMethod.apply(<span class="hljs-keyword">this</span>, args);
        }
    }
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{
        @upperCase
        <span class="hljs-attr">name</span>: string = <span class="hljs-string">'zhufeng'</span>
        public <span class="hljs-keyword">static</span> age: number = <span class="hljs-number">10</span>
        <span class="hljs-keyword">constructor</span>() { }
        @noEnumerable
        getName() {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">this</span>.name);
        }
        @toNumber
        sum(...args: any[]) {
            <span class="hljs-keyword">return</span> args.reduce(<span class="hljs-function">(<span class="hljs-params">accu: number, item: number</span>) =&gt;</span> accu + item, <span class="hljs-number">0</span>);
        }
    }
    <span class="hljs-keyword">let</span> p: Person = <span class="hljs-keyword">new</span> Person();
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> attr <span class="hljs-keyword">in</span> p) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'attr='</span>, attr);
    }
    p.name = <span class="hljs-string">'jiagou'</span>;
    p.getName();
    <span class="hljs-built_in">console</span>.log(p.sum(<span class="hljs-string">"1"</span>, <span class="hljs-string">"2"</span>, <span class="hljs-string">"3"</span>));
}
</code></pre>
            <h4 id="t525.8.3 参数装饰器">5.8.3 参数装饰器 <a href="#t525.8.3%20%E5%8F%82%E6%95%B0%E8%A3%85%E9%A5%B0%E5%99%A8">
                    # </a></h4>
            <ul>
                <li>会在运行时当作函数被调用，可以使用参数装饰器为类的原型增加一些元数据<ul>
                        <li>第1个参数对于静态成员是类的构造函数，对于实例成员是类的原型对象</li>
                        <li>第2个参数的名称</li>
                        <li>第3个参数在函数列表中的索引</li>
                    </ul>
                </li>
            </ul>
            <pre><code class="lang-js">namespace d {
    interface Person {
        <span class="hljs-attr">age</span>: number;
    }
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addAge</span>(<span class="hljs-params">target: any, methodName: string, paramsIndex: number</span>) </span>{
        <span class="hljs-built_in">console</span>.log(target);
        <span class="hljs-built_in">console</span>.log(methodName);
        <span class="hljs-built_in">console</span>.log(paramsIndex);
        target.age = <span class="hljs-number">10</span>;
    }
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{
        login(username: string, @addAge password: string) {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">this</span>.age, username, password);
        }
    }
    <span class="hljs-keyword">let</span> p = <span class="hljs-keyword">new</span> Person();
    p.login(<span class="hljs-string">'zhufeng'</span>, <span class="hljs-string">'123456'</span>)
}
</code></pre>
            <h4 id="t535.8.4 装饰器执行顺序">5.8.4 装饰器执行顺序 <a
                    href="#t535.8.4%20%E8%A3%85%E9%A5%B0%E5%99%A8%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F">
                    # </a></h4>
            <ul>
                <li>有多个参数装饰器时：从最后一个参数依次向前执行</li>
                <li>方法和方法参数中参数装饰器先执行。</li>
                <li>类装饰器总是最后执行</li>
                <li>方法和属性装饰器，谁在前面谁先执行。因为参数属于方法一部分，所以参数会一直紧紧挨着方法执行</li>
                <li>类比React组件的componentDidMount 先上后下、先内后外</li>
            </ul>
            <pre><code class="lang-js">namespace e {
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Class1Decorator</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">target: any</span>) </span>{
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"类1装饰器"</span>);
        }
    }
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Class2Decorator</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">target: any</span>) </span>{
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"类2装饰器"</span>);
        }
    }
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MethodDecorator</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">target: any, methodName: string, descriptor: PropertyDescriptor</span>) </span>{
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"方法装饰器"</span>);
        }
    }
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Param1Decorator</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">target: any, methodName: string, paramIndex: number</span>) </span>{
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"参数1装饰器"</span>);
        }
    }
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Param2Decorator</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">target: any, methodName: string, paramIndex: number</span>) </span>{
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"参数2装饰器"</span>);
        }
    }
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PropertyDecorator</span>(<span class="hljs-params">name: string</span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">target: any, propertyName: string</span>) </span>{
            <span class="hljs-built_in">console</span>.log(name + <span class="hljs-string">"属性装饰器"</span>);
        }
    }

    @Class1Decorator()
    @Class2Decorator()
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{
        @PropertyDecorator(<span class="hljs-string">'name'</span>)
        <span class="hljs-attr">name</span>: string = <span class="hljs-string">'zhufeng'</span>;
        @PropertyDecorator(<span class="hljs-string">'age'</span>)
        <span class="hljs-attr">age</span>: number = <span class="hljs-number">10</span>;
        @MethodDecorator()
        greet(@Param1Decorator() p1: string, @Param2Decorator() p2: string) { }
    }
}
<span class="hljs-comment">/**
name属性装饰器
age属性装饰器
参数2装饰器
参数1装饰器
方法装饰器
类2装饰器
类1装饰器
 */</span>
</code></pre>
            <h3 id="t545.9 抽象类">5.9 抽象类 <a href="#t545.9%20%E6%8A%BD%E8%B1%A1%E7%B1%BB">
                    # </a></h3>
            <ul>
                <li>抽象描述一种抽象的概念，无法被实例化，只能被继承</li>
                <li>无法创建抽象类的实例</li>
                <li>抽象方法不能在抽象类中实现，只能在抽象类的具体子类中实现，而且必须实现</li>
            </ul>
            <pre><code class="lang-js">abstract <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span> </span>{
    name!:string;
    abstract speak():<span class="hljs-keyword">void</span>;
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Cat</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span></span>{
    speak(){
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'喵喵喵'</span>);
    }
}
<span class="hljs-keyword">let</span> animal = <span class="hljs-keyword">new</span> Animal();<span class="hljs-comment">//Cannot create an instance of an abstract class</span>
animal.speak();
<span class="hljs-keyword">let</span> cat = <span class="hljs-keyword">new</span> Cat();
cat.speak();
</code></pre>
            <table>
                <thead>
                    <tr>
                        <th style="text-align:left">访问控制修饰符</th>
                        <th style="text-align:left">private protected public</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td style="text-align:left">只读属性</td>
                        <td style="text-align:left">readonly</td>
                    </tr>
                    <tr>
                        <td style="text-align:left">静态属性</td>
                        <td style="text-align:left">static</td>
                    </tr>
                    <tr>
                        <td style="text-align:left">抽象类、抽象方法</td>
                        <td style="text-align:left">abstract</td>
                    </tr>
                </tbody>
            </table>
            <h3 id="t555.10 抽象方法">5.10 抽象方法 <a href="#t555.10%20%E6%8A%BD%E8%B1%A1%E6%96%B9%E6%B3%95">
                    # </a></h3>
            <ul>
                <li>抽象类和方法不包含具体实现，必须在子类中实现</li>
                <li>抽象方法只能出现在抽象类中</li>
                <li>子类可以对抽象类进行不同的实现</li>
            </ul>
            <pre><code class="lang-js">abstract <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span></span>{
    abstract speak():<span class="hljs-keyword">void</span>;
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> <span class="hljs-keyword">extends</span>  <span class="hljs-title">Animal</span></span>{
    speak(){
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'小狗汪汪汪'</span>);
    }
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Cat</span> <span class="hljs-keyword">extends</span>  <span class="hljs-title">Animal</span></span>{
    speak(){
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'小猫喵喵喵'</span>);
    }
}
<span class="hljs-keyword">let</span> dog=<span class="hljs-keyword">new</span> Dog();
<span class="hljs-keyword">let</span> cat=<span class="hljs-keyword">new</span> Cat();
dog.speak();
cat.speak();
</code></pre>
            <h3 id="t565.11 重写(override) vs 重载(overload)">5.11 重写(override) vs 重载(overload) <a
                    href="#t565.11%20%E9%87%8D%E5%86%99(override)%20vs%20%E9%87%8D%E8%BD%BD(overload)">
                    # </a></h3>
            <ul>
                <li>重写是指子类重写继承自父类中的方法</li>
                <li>重载是指为同一个函数提供多个类型定义</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span></span>{
    speak(word:string):string{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'动作叫:'</span>+word;
    }
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Cat</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span></span>{
    speak(word:string):string{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'猫叫:'</span>+word;
    }
}
<span class="hljs-keyword">let</span> cat = <span class="hljs-keyword">new</span> Cat();
<span class="hljs-built_in">console</span>.log(cat.speak(<span class="hljs-string">'hello'</span>));
<span class="hljs-comment">//--------------------------------------------</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">double</span>(<span class="hljs-params">val:number</span>):<span class="hljs-title">number</span>
<span class="hljs-title">function</span> <span class="hljs-title">double</span>(<span class="hljs-params">val:string</span>):<span class="hljs-title">string</span>
<span class="hljs-title">function</span> <span class="hljs-title">double</span>(<span class="hljs-params">val:any</span>):<span class="hljs-title">any</span></span>{
  <span class="hljs-keyword">if</span>(<span class="hljs-keyword">typeof</span> val == <span class="hljs-string">'number'</span>){
    <span class="hljs-keyword">return</span> val *<span class="hljs-number">2</span>;
  }
  <span class="hljs-keyword">return</span> val + val;
}

<span class="hljs-keyword">let</span> r = double(<span class="hljs-number">1</span>);
<span class="hljs-built_in">console</span>.log(r);
</code></pre>
            <h3 id="t575.12 继承 vs 多态">5.12 继承 vs 多态 <a href="#t575.12%20%E7%BB%A7%E6%89%BF%20vs%20%E5%A4%9A%E6%80%81">
                    # </a></h3>
            <ul>
                <li>继承(Inheritance)子类继承父类，子类除了拥有父类的所有特性外，还有一些更具体的特性</li>
                <li>多态(Polymorphism)由继承而产生了相关的不同的类，对同一个方法可以有不同的行为</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span></span>{
    speak(word:string):string{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'Animal: '</span>+word;
    }
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Cat</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span></span>{
    speak(word:string):string{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'Cat:'</span>+word;
    }
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span></span>{
    speak(word:string):string{
        <span class="hljs-keyword">return</span> <span class="hljs-string">'Dog:'</span>+word;
    }
}
<span class="hljs-keyword">let</span> cat = <span class="hljs-keyword">new</span> Cat();
<span class="hljs-built_in">console</span>.log(cat.speak(<span class="hljs-string">'hello'</span>));
<span class="hljs-keyword">let</span> dog = <span class="hljs-keyword">new</span> Dog();
<span class="hljs-built_in">console</span>.log(dog.speak(<span class="hljs-string">'hello'</span>));
</code></pre>
            <h2 id="t586. 接口">6. 接口 <a href="#t586.%20%E6%8E%A5%E5%8F%A3"> #
                </a></h2>
            <ul>
                <li>接口一方面可以在面向对象编程中表示为<code>行为的抽象</code>，另外可以用来描述<code>对象的形状</code></li>
                <li>接口就是把一些类中共有的属性和方法抽象出来,可以用来约束实现此接口的类</li>
                <li>一个类可以继承另一个类并实现多个接口</li>
                <li>接口像插件一样是用来增强类的，而抽象类是具体类的抽象概念</li>
                <li>一个类可以实现多个接口，一个接口也可以被多个类实现，但一个类的可以有多个子类，但只能有一个父类</li>
            </ul>
            <h3 id="t596.1 接口">6.1 接口 <a href="#t596.1%20%E6%8E%A5%E5%8F%A3"> #
                </a></h3>
            <ul>
                <li>interface中可以用分号或者逗号分割每一项，也可以什么都不加</li>
            </ul>
            <h4 id="t606.1.1 对象的形状">6.1.1 对象的形状 <a href="#t606.1.1%20%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%BD%A2%E7%8A%B6">
                    # </a></h4>
            <pre><code class="lang-js"><span class="hljs-comment">//接口可以用来描述`对象的形状`,少属性或者多属性都会报错</span>
interface Speakable{
    speak():<span class="hljs-keyword">void</span>;
    name?:string;<span class="hljs-comment">//？表示可选属性</span>
}

<span class="hljs-keyword">let</span> speakman:Speakable = {
    speak(){},<span class="hljs-comment">//少属性会报错</span>
    name,
    age<span class="hljs-comment">//多属性也会报错</span>
}
</code></pre>
            <h4 id="t616.1.2 行为的抽象">6.1.2 行为的抽象 <a href="#t616.1.2%20%E8%A1%8C%E4%B8%BA%E7%9A%84%E6%8A%BD%E8%B1%A1">
                    # </a></h4>
            <pre><code class="lang-js"><span class="hljs-comment">//接口可以在面向对象编程中表示为行为的抽象</span>
interface Speakable{
    speak():<span class="hljs-keyword">void</span>;
}
interface Eatable{
    eat():<span class="hljs-keyword">void</span>
}
<span class="hljs-comment">//一个类可以实现多个接口</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> <span class="hljs-title">implements</span> <span class="hljs-title">Speakable</span>,<span class="hljs-title">Eatable</span></span>{
    speak(){
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Person说话'</span>);
    }
    eat(){}
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TangDuck</span> <span class="hljs-title">implements</span> <span class="hljs-title">Speakable</span></span>{
    speak(){
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'TangDuck说话'</span>);
    }
    eat(){}
}
</code></pre>
            <h4 id="t626.1.3 任意属性">6.1.3 任意属性 <a href="#t626.1.3%20%E4%BB%BB%E6%84%8F%E5%B1%9E%E6%80%A7">
                    # </a></h4>
            <pre><code class="lang-js"><span class="hljs-comment">//无法预先知道有哪些新的属性的时候,可以使用 `[propName:string]:any`,propName名字是任意的</span>
interface Person {
  readonly id: number;
  name: string;
  [propName: string]: any;
}

<span class="hljs-keyword">let</span> p1 = {
  <span class="hljs-attr">id</span>:<span class="hljs-number">1</span>,
  <span class="hljs-attr">name</span>:<span class="hljs-string">'zhufeng'</span>,
  <span class="hljs-attr">age</span>:<span class="hljs-number">10</span>
}
</code></pre>
            <h3 id="t636.2 接口的继承">6.2 接口的继承 <a href="#t636.2%20%E6%8E%A5%E5%8F%A3%E7%9A%84%E7%BB%A7%E6%89%BF">
                    # </a></h3>
            <ul>
                <li>一个接口可以继承自另外一个接口</li>
            </ul>
            <pre><code class="lang-js">interface Speakable {
    speak(): <span class="hljs-keyword">void</span>
}
interface SpeakChinese extends Speakable {
    speakChinese(): <span class="hljs-keyword">void</span>
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> <span class="hljs-title">implements</span> <span class="hljs-title">SpeakChinese</span> </span>{
    speak() {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Person'</span>)
    }
    speakChinese() {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'speakChinese'</span>)
    }
}
</code></pre>
            <h3 id="t646.3 readonly">6.3 readonly <a href="#t646.3%20readonly"> # </a></h3>
            <ul>
                <li>用 readonly 定义只读属性可以避免由于多人协作或者项目较为复杂等因素造成对象的值被重写</li>
            </ul>
            <pre><code class="lang-js">interface Person{
  readonly id:number;
  name:string
}
<span class="hljs-keyword">let</span> tom:Person = {
  <span class="hljs-attr">id</span> :<span class="hljs-number">1</span>,
  <span class="hljs-attr">name</span>:<span class="hljs-string">'zhufeng'</span>
}
tom.id = <span class="hljs-number">1</span>;
</code></pre>
            <h3 id="t656.4 函数类型接口">6.4 函数类型接口 <a
                    href="#t656.4%20%E5%87%BD%E6%95%B0%E7%B1%BB%E5%9E%8B%E6%8E%A5%E5%8F%A3">
                    # </a></h3>
            <ul>
                <li>对方法传入的参数和返回值进行约束</li>
            </ul>
            <pre><code class="lang-js">interface discount{
  (price:number):number
}
<span class="hljs-keyword">let</span> cost:discount = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">price:number</span>):<span class="hljs-title">number</span></span>{
   <span class="hljs-keyword">return</span> price * <span class="hljs-number">.8</span>;
}
</code></pre>
            <h3 id="t666.5 可索引接口">6.5 可索引接口 <a href="#t666.5%20%E5%8F%AF%E7%B4%A2%E5%BC%95%E6%8E%A5%E5%8F%A3">
                    # </a></h3>
            <ul>
                <li>对数组和对象进行约束</li>
                <li>userInterface 表示<code>index</code>的类型是 number，那么值的类型必须是 string</li>
                <li>UserInterface2 表示：<code>index</code> 的类型是 string，那么值的类型必须是 string</li>
            </ul>
            <pre><code class="lang-js">interface UserInterface {
  [index:number]:string
}
<span class="hljs-keyword">let</span> arr:UserInterface = [<span class="hljs-string">'zfpx1'</span>,<span class="hljs-string">'zfpx2'</span>];
<span class="hljs-built_in">console</span>.log(arr);

interface UserInterface2 {
  [index:string]:string
}
<span class="hljs-keyword">let</span> obj:UserInterface2 = {<span class="hljs-attr">name</span>:<span class="hljs-string">'zhufeng'</span>};

</code></pre>
            <h3 id="t676.6 类接口">6.6 类接口 <a href="#t676.6%20%E7%B1%BB%E6%8E%A5%E5%8F%A3">
                    # </a></h3>
            <ul>
                <li>对类的约束</li>
            </ul>
            <pre><code class="lang-js">interface Speakable {
    <span class="hljs-attr">name</span>: string;
    speak(words: string): <span class="hljs-keyword">void</span>
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> <span class="hljs-title">implements</span> <span class="hljs-title">Speakable</span> </span>{
    name!: string;
    speak(words:string) {
        <span class="hljs-built_in">console</span>.log(words);
    }
}
<span class="hljs-keyword">let</span> dog = <span class="hljs-keyword">new</span> Dog();
dog.speak(<span class="hljs-string">'汪汪汪'</span>);
</code></pre>
            <h3 id="t686.7 构造函数的类型">6.7 构造函数的类型 <a
                    href="#t686.7%20%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E7%9A%84%E7%B1%BB%E5%9E%8B">
                    # </a></h3>
            <ul>
                <li>在 TypeScript 中，我们可以用 interface 来描述类</li>
                <li>同时也可以使用interface里特殊的new()关键字来描述类的构造函数类型</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span></span>{
  <span class="hljs-keyword">constructor</span>(public name:string){
  }
}
<span class="hljs-comment">//不加new是修饰函数的,加new是修饰类的</span>
interface WithNameClass{
  <span class="hljs-keyword">new</span>(name:string):Animal
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createAnimal</span>(<span class="hljs-params">clazz:WithNameClass,name:string</span>)</span>{
   <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> clazz(name);
}
<span class="hljs-keyword">let</span> a = createAnimal(Animal,<span class="hljs-string">'zhufeng'</span>);
<span class="hljs-built_in">console</span>.log(a.name);
</code></pre>
            <h3 id="t696.8  抽象类 vs 接口">6.8 抽象类 vs 接口 <a
                    href="#t696.8%20%20%E6%8A%BD%E8%B1%A1%E7%B1%BB%20vs%20%E6%8E%A5%E5%8F%A3">
                    # </a></h3>
            <ul>
                <li>不同类之间公有的属性或方法，可以抽象成一个接口（Interfaces）</li>
                <li>而抽象类是供其他类继承的基类，抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现</li>
                <li>抽象类本质是一个无法被实例化的类，其中能够实现方法和初始化属性，而接口仅能够用于描述,既不提供方法的实现，也不为属性进行初始化</li>
                <li>一个类可以继承一个类或抽象类，但可以实现（implements）多个接口</li>
                <li>抽象类也可以实现接口</li>
            </ul>
            <pre><code class="lang-js">abstract <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span></span>{
    <span class="hljs-attr">name</span>:string;
    <span class="hljs-keyword">constructor</span>(name:string){
      <span class="hljs-keyword">this</span>.name = name;
    }
    abstract speak():<span class="hljs-keyword">void</span>;
  }
interface Flying{
      fly():<span class="hljs-keyword">void</span>
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Duck</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span> <span class="hljs-title">implements</span> <span class="hljs-title">Flying</span></span>{
      speak(){
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'汪汪汪'</span>);
      }
      fly(){
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'我会飞'</span>);
      }
}
<span class="hljs-keyword">let</span> duck = <span class="hljs-keyword">new</span> Duck(<span class="hljs-string">'zhufeng'</span>);
duck.speak();
duck.fly();
</code></pre>
            <h2 id="t707. 泛型">7. 泛型 <a href="#t707.%20%E6%B3%9B%E5%9E%8B"> #
                </a></h2>
            <ul>
                <li>泛型（Generics）是指在定义函数、接口或类的时候，不预先指定具体的类型，而在使用的时候再指定类型的一种特性</li>
                <li>泛型<code>T</code>作用域只限于函数内部使用</li>
            </ul>
            <h3 id="t717.1 泛型函数">7.1 泛型函数 <a href="#t717.1%20%E6%B3%9B%E5%9E%8B%E5%87%BD%E6%95%B0">
                    # </a></h3>
            <ul>
                <li>首先，我们来实现一个函数 createArray，它可以创建一个指定长度的数组，同时将每一项都填充一个默认值</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createArray</span>(<span class="hljs-params">length: number, value: any</span>): <span class="hljs-title">Array</span>&lt;<span class="hljs-title">any</span>&gt; </span>{
  <span class="hljs-keyword">let</span> result: any = [];
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; length; i++) {
    result[i] = value;
  }
  <span class="hljs-keyword">return</span> result;
}
<span class="hljs-keyword">let</span> result = createArray(<span class="hljs-number">3</span>,<span class="hljs-string">'x'</span>);
<span class="hljs-built_in">console</span>.log(result);
</code></pre>
            <p>使用了泛型</p>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createArray</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">length: number, value: T</span>): <span class="hljs-title">Array</span>&lt;<span class="hljs-title">T</span>&gt; </span>{
    <span class="hljs-keyword">let</span> result: T[] = [];
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; length; i++) {
      result[i] = value;
    }
    <span class="hljs-keyword">return</span> result;
  }
<span class="hljs-keyword">let</span> result = createArray2&lt;string&gt;(<span class="hljs-number">3</span>,<span class="hljs-string">'x'</span>);
<span class="hljs-built_in">console</span>.log(result);
</code></pre>
            <h3 id="t727.2 类数组">7.2 类数组 <a href="#t727.2%20%E7%B1%BB%E6%95%B0%E7%BB%84">
                    # </a></h3>
            <ul>
                <li>类数组（Array-like Object）不是数组类型，比如 <code>arguments</code></li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sum</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> args: IArguments = <span class="hljs-built_in">arguments</span>;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; args.length; i++) {
        <span class="hljs-built_in">console</span>.log(args[i]);
    }
}
sum(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>);

<span class="hljs-keyword">let</span> root = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>);
<span class="hljs-keyword">let</span> children: HTMLCollection = (root <span class="hljs-keyword">as</span> HTMLElement).children;
children.length;
<span class="hljs-keyword">let</span> nodeList: NodeList = (root <span class="hljs-keyword">as</span> HTMLElement).childNodes;
nodeList.length;
</code></pre>
            <h3 id="t737.3 泛型类">7.3 泛型类 <a href="#t737.3%20%E6%B3%9B%E5%9E%8B%E7%B1%BB">
                    # </a></h3>
            <h4 id="t747.3.1 泛型类">7.3.1 泛型类 <a href="#t747.3.1%20%E6%B3%9B%E5%9E%8B%E7%B1%BB">
                    # </a></h4>
            <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyArray</span>&lt;<span class="hljs-title">T</span>&gt;</span>{
    private list:T[]=[];
    add(value:T) {
        <span class="hljs-keyword">this</span>.list.push(value);
    }
    getMax():T {
        <span class="hljs-keyword">let</span> result=<span class="hljs-keyword">this</span>.list[<span class="hljs-number">0</span>];
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>;i&lt;<span class="hljs-keyword">this</span>.list.length;i++){
            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.list[i]&gt;result) {
                result=<span class="hljs-keyword">this</span>.list[i];
            }
        }
        <span class="hljs-keyword">return</span> result;
    }
}
<span class="hljs-keyword">let</span> arr=<span class="hljs-keyword">new</span> MyArray();
arr.add(<span class="hljs-number">1</span>); arr.add(<span class="hljs-number">2</span>); arr.add(<span class="hljs-number">3</span>);
<span class="hljs-keyword">let</span> ret = arr.getMax();
<span class="hljs-built_in">console</span>.log(ret);
</code></pre>
            <h4 id="t757.3.2 泛型与 new">7.3.2 泛型与 new <a href="#t757.3.2%20%E6%B3%9B%E5%9E%8B%E4%B8%8E%20new">
                    # </a></h4>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">factory</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">type: {new(</span>):<span class="hljs-title">T</span>}): <span class="hljs-title">T</span> </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> type(); <span class="hljs-comment">// This expression is not constructable.</span>
}
</code></pre>
            <h3 id="t767.5 泛型接口">7.5 泛型接口 <a href="#t767.5%20%E6%B3%9B%E5%9E%8B%E6%8E%A5%E5%8F%A3">
                    # </a></h3>
            <ul>
                <li>泛型接口可以用来约束函数</li>
            </ul>
            <pre><code class="lang-js">interface Calculate{
  &lt;T&gt;(a:T,<span class="hljs-attr">b</span>:T):T
}
<span class="hljs-keyword">let</span> add:Calculate = <span class="hljs-function"><span class="hljs-keyword">function</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">a:T,b:T</span>)</span>{
  <span class="hljs-keyword">return</span> a;
}
add&lt;number&gt;(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>);

</code></pre>
            <h3 id="t777.6 多个类型参数">7.6 多个类型参数 <a
                    href="#t777.6%20%E5%A4%9A%E4%B8%AA%E7%B1%BB%E5%9E%8B%E5%8F%82%E6%95%B0">
                    # </a></h3>
            <ul>
                <li>泛型可以有多个</li>
            </ul>
            <pre><code class="lang-js">function swap&lt;A,B&gt;(tuple:[A,B]):[B,A]{
  return [tuple[1],tuple[0]];
}
let swapped = swap&lt;string,number&gt;(['a',1]);
console.log(swapped);
console.log(swapped[0].toFixed(2));
console.log(swapped[1].length);
</code></pre>
            <h3 id="t787.7 默认泛型类型">7.7 默认泛型类型 <a
                    href="#t787.7%20%E9%BB%98%E8%AE%A4%E6%B3%9B%E5%9E%8B%E7%B1%BB%E5%9E%8B">
                    # </a></h3>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createArray3</span>&lt;<span class="hljs-title">T</span>=<span class="hljs-title">number</span>&gt;(<span class="hljs-params">length: number, value: T</span>): <span class="hljs-title">Array</span>&lt;<span class="hljs-title">T</span>&gt; </span>{
  <span class="hljs-keyword">let</span> result: T[] = [];
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; length; i++) {
    result[i] = value;
  }
  <span class="hljs-keyword">return</span> result;
}
<span class="hljs-keyword">let</span> result2 = createArray3(<span class="hljs-number">3</span>,<span class="hljs-string">'x'</span>);
<span class="hljs-built_in">console</span>.log(result2);
</code></pre>
            <h3 id="t797.8 泛型约束">7.8 泛型约束 <a href="#t797.8%20%E6%B3%9B%E5%9E%8B%E7%BA%A6%E6%9D%9F">
                    # </a></h3>
            <ul>
                <li>在函数中使用泛型的时候，由于预先并不知道泛型的类型，所以不能随意访问相应类型的属性或方法。</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logger</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">val: T</span>) </span>{
    <span class="hljs-built_in">console</span>.log(val.length); <span class="hljs-comment">//直接访问会报错</span>
}
<span class="hljs-comment">//可以让泛型继承一个接口</span>
interface LengthWise {
    <span class="hljs-attr">length</span>: number
}
<span class="hljs-comment">//可以让泛型继承一个接口</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logger2</span>&lt;<span class="hljs-title">T</span> <span class="hljs-title">extends</span> <span class="hljs-title">LengthWise</span>&gt;(<span class="hljs-params">val: T</span>) </span>{
    <span class="hljs-built_in">console</span>.log(val.length)
}
logger2(<span class="hljs-string">'zhufeng'</span>);
logger2(<span class="hljs-number">1</span>);
</code></pre>
            <h3 id="t807.9 泛型接口">7.9 泛型接口 <a href="#t807.9%20%E6%B3%9B%E5%9E%8B%E6%8E%A5%E5%8F%A3">
                    # </a></h3>
            <ul>
                <li>定义接口的时候也可以指定泛型 </li>
            </ul>
            <pre><code class="lang-js">interface Cart&lt;T&gt;{
  <span class="hljs-attr">list</span>:T[]
}
<span class="hljs-keyword">let</span> cart:Cart&lt;{<span class="hljs-attr">name</span>:string,<span class="hljs-attr">price</span>:number}&gt; = {
  <span class="hljs-attr">list</span>:[{<span class="hljs-attr">name</span>:<span class="hljs-string">'zhufeng'</span>,<span class="hljs-attr">price</span>:<span class="hljs-number">10</span>}]
}
<span class="hljs-built_in">console</span>.log(cart.list[<span class="hljs-number">0</span>].name,cart.list[<span class="hljs-number">0</span>].price);
</code></pre>
            <h3 id="t817.10 compose">7.10 compose <a href="#t817.10%20compose"> # </a></h3>
            <p><a href="https://gitee.com/zhufengpeixun/redux/blob/master/src/compose.ts">compose</a></p>
            <pre><code class="lang-js"><span class="hljs-keyword">import</span> compose <span class="hljs-keyword">from</span> <span class="hljs-string">"."</span>;
<span class="hljs-comment">/* zero functions */</span>
<span class="hljs-built_in">console</span>.log(compose()&lt;string&gt;(<span class="hljs-string">"zhufeng"</span>));
<span class="hljs-comment">/* one functions */</span>
interface F{
    (a:string):string
}
<span class="hljs-keyword">let</span> f: F = (a:string):<span class="hljs-function"><span class="hljs-params">string</span>=&gt;</span>a+<span class="hljs-string">'f'</span>;
<span class="hljs-built_in">console</span>.log(compose&lt;F&gt;(f)(<span class="hljs-string">"zhufeng"</span>));
<span class="hljs-comment">/* two functions */</span>
type A = string;
type R = string;
type T = string[];

<span class="hljs-keyword">let</span> f1 = (a: A): <span class="hljs-function"><span class="hljs-params">R</span> =&gt;</span> a + <span class="hljs-string">"f1"</span>;
<span class="hljs-keyword">let</span> f2 = (...a: T): <span class="hljs-function"><span class="hljs-params">A</span> =&gt;</span> a + <span class="hljs-string">"f2"</span>;
<span class="hljs-built_in">console</span>.log(compose&lt;A,T,R&gt;(f1,f2)(<span class="hljs-string">"zhufeng"</span>));
</code></pre>
            <h3 id="t827.11 泛型类型别名">7.11 泛型类型别名 <a
                    href="#t827.11%20%E6%B3%9B%E5%9E%8B%E7%B1%BB%E5%9E%8B%E5%88%AB%E5%90%8D">
                    # </a></h3>
            <ul>
                <li>泛型类型别名可以表达更复杂的类型</li>
            </ul>
            <pre><code class="lang-js">type Cart&lt;T&gt; = {<span class="hljs-attr">list</span>:T[]} | T[];
<span class="hljs-keyword">let</span> c1:Cart&lt;string&gt; = {<span class="hljs-attr">list</span>:[<span class="hljs-string">'1'</span>]};
<span class="hljs-keyword">let</span> c2:Cart&lt;number&gt; = [<span class="hljs-number">1</span>];
</code></pre>
            <h3 id="t837.12 泛型接口 vs 泛型类型别名">7.12 泛型接口 vs 泛型类型别名 <a
                    href="#t837.12%20%E6%B3%9B%E5%9E%8B%E6%8E%A5%E5%8F%A3%20vs%20%E6%B3%9B%E5%9E%8B%E7%B1%BB%E5%9E%8B%E5%88%AB%E5%90%8D">
                    # </a></h3>
            <ul>
                <li>接口创建了一个新的名字，它可以在其他任意地方被调用。而类型别名并不创建新的名字，例如报错信息就不会使用别名</li>
                <li>类型别名不能被 extends和 implements,这时我们应该尽量使用接口代替类型别名</li>
                <li>当我们需要使用联合类型或者元组类型的时候，类型别名会更合适</li>
            </ul>
            <h2 id="t848.结构类型系统">8.结构类型系统 <a href="#t848.%E7%BB%93%E6%9E%84%E7%B1%BB%E5%9E%8B%E7%B3%BB%E7%BB%9F">
                    # </a></h2>
            <h3 id="t858.1 接口的兼容性">8.1 接口的兼容性 <a
                    href="#t858.1%20%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%85%BC%E5%AE%B9%E6%80%A7">
                    # </a></h3>
            <ul>
                <li>如果传入的变量和声明的类型不匹配，TS就会进行兼容性检查</li>
                <li>原理是<code>Duck-Check</code>,就是说只要目标类型中声明的属性变量在源类型中都存在就是兼容的</li>
            </ul>
            <pre><code class="lang-js">interface Animal {
    <span class="hljs-attr">name</span>: string;
    age: number;
}

interface Person {
    <span class="hljs-attr">name</span>: string;
    age: number;
    gender: number
}
<span class="hljs-comment">// 要判断目标类型`Person`是否能够兼容输入的源类型`Animal`</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getName</span>(<span class="hljs-params">animal: Animal</span>): <span class="hljs-title">string</span> </span>{
    <span class="hljs-keyword">return</span> animal.name;
}

<span class="hljs-keyword">let</span> p = {
    <span class="hljs-attr">name</span>: <span class="hljs-string">'zhufeng'</span>,
    <span class="hljs-attr">age</span>: <span class="hljs-number">10</span>,
    <span class="hljs-attr">gender</span>: <span class="hljs-number">0</span>
}

getName(p);
<span class="hljs-comment">//只有在传参的时候两个变量之间才会进行兼容性的比较，赋值的时候并不会比较,会直接报错</span>
<span class="hljs-keyword">let</span> a: Animal = {
    <span class="hljs-attr">name</span>: <span class="hljs-string">'zhufeng'</span>,
    <span class="hljs-attr">age</span>: <span class="hljs-number">10</span>,
    <span class="hljs-attr">gender</span>: <span class="hljs-number">0</span>
}
</code></pre>
            <h3 id="t868.2 基本类型的兼容性">8.2 基本类型的兼容性 <a
                    href="#t868.2%20%E5%9F%BA%E6%9C%AC%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%85%BC%E5%AE%B9%E6%80%A7">
                    # </a></h3>
            <pre><code class="lang-js"><span class="hljs-comment">//基本数据类型也有兼容性判断</span>
<span class="hljs-keyword">let</span> num : string|number;
<span class="hljs-keyword">let</span> str:string=<span class="hljs-string">'zhufeng'</span>;
num = str;

<span class="hljs-comment">//只要有toString()方法就可以赋给字符串变量</span>
<span class="hljs-keyword">let</span> num2 : {
  toString():string
}

<span class="hljs-keyword">let</span> str2:string=<span class="hljs-string">'jiagou'</span>;
num2 = str2;
</code></pre>
            <h3 id="t878.3 类的兼容性">8.3 类的兼容性 <a href="#t878.3%20%E7%B1%BB%E7%9A%84%E5%85%BC%E5%AE%B9%E6%80%A7">
                    # </a></h3>
            <ul>
                <li>在TS中是结构类型系统，只会对比结构而不在意类型</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span></span>{
    <span class="hljs-attr">name</span>:string
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Bird</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span></span>{
   <span class="hljs-attr">swing</span>:number
}

<span class="hljs-keyword">let</span> a:Animal;
a = <span class="hljs-keyword">new</span> Bird();

<span class="hljs-keyword">let</span> b:Bird;
<span class="hljs-comment">//并不是父类兼容子类，子类不兼容父类</span>
b = <span class="hljs-keyword">new</span> Animal();
</code></pre>
            <pre><code class="lang-js">
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span></span>{
  <span class="hljs-attr">name</span>:string
}
<span class="hljs-comment">//如果父类和子类结构一样，也可以的</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Bird</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span></span>{}

<span class="hljs-keyword">let</span> a:Animal;
a = <span class="hljs-keyword">new</span> Bird();

<span class="hljs-keyword">let</span> b:Bird;
b = <span class="hljs-keyword">new</span> Animal();

</code></pre>
            <pre><code class="lang-js"><span class="hljs-comment">//甚至没有关系的两个类的实例也是可以的</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span></span>{
  <span class="hljs-attr">name</span>:string
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Bird</span></span>{
  <span class="hljs-attr">name</span>:string
}
<span class="hljs-keyword">let</span> a:Animal ;
a = <span class="hljs-keyword">new</span> Bird();
<span class="hljs-keyword">let</span> b:Bird;
b = <span class="hljs-keyword">new</span> Animal();
</code></pre>
            <h3 id="t888.4 函数的兼容性">8.4 函数的兼容性 <a
                    href="#t888.4%20%E5%87%BD%E6%95%B0%E7%9A%84%E5%85%BC%E5%AE%B9%E6%80%A7">
                    # </a></h3>
            <ul>
                <li>比较函数的时候是要先比较函数的参数，再比较函数的返回值</li>
            </ul>
            <h4 id="t898.4.1 比较参数">8.4.1 比较参数 <a href="#t898.4.1%20%E6%AF%94%E8%BE%83%E5%8F%82%E6%95%B0">
                    # </a></h4>
            <pre><code class="lang-js">type sumFunc = <span class="hljs-function">(<span class="hljs-params">a:number,b:number</span>)=&gt;</span>number;
<span class="hljs-keyword">let</span> sum:sumFunc;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">f1</span>(<span class="hljs-params">a:number,b:number</span>):<span class="hljs-title">number</span></span>{
  <span class="hljs-keyword">return</span> a+b;
}
sum = f1;

<span class="hljs-comment">//可以省略一个参数</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">f2</span>(<span class="hljs-params">a:number</span>):<span class="hljs-title">number</span></span>{
   <span class="hljs-keyword">return</span> a;
}
sum = f2;

<span class="hljs-comment">//可以省略二个参数</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">f3</span>(<span class="hljs-params"></span>):<span class="hljs-title">number</span></span>{
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
sum = f3;

 <span class="hljs-comment">//多一个参数可不行</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">f4</span>(<span class="hljs-params">a:number,b:number,c:number</span>)</span>{
    <span class="hljs-keyword">return</span> a+b+c;
}
sum = f4;
</code></pre>
            <h4 id="t908.4.2 比较返回值">8.4.2 比较返回值 <a href="#t908.4.2%20%E6%AF%94%E8%BE%83%E8%BF%94%E5%9B%9E%E5%80%BC">
                    # </a></h4>
            <pre><code class="lang-js">type GetPerson = <span class="hljs-function"><span class="hljs-params">()</span>=&gt;</span>{<span class="hljs-attr">name</span>:string,<span class="hljs-attr">age</span>:number};
<span class="hljs-keyword">let</span> getPerson:GetPerson;
<span class="hljs-comment">//返回值一样可以</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">g1</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">return</span> {<span class="hljs-attr">name</span>:<span class="hljs-string">'zhufeng'</span>,<span class="hljs-attr">age</span>:<span class="hljs-number">10</span>};
}
getPerson = g1;
<span class="hljs-comment">//返回值多一个属性也可以</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">g2</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">return</span> {<span class="hljs-attr">name</span>:<span class="hljs-string">'zhufeng'</span>,<span class="hljs-attr">age</span>:<span class="hljs-number">10</span>,<span class="hljs-attr">gender</span>:<span class="hljs-string">'male'</span>};
}
getPerson = g2;
<span class="hljs-comment">//返回值少一个属性可不行</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">g3</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">return</span> {<span class="hljs-attr">name</span>:<span class="hljs-string">'zhufeng'</span>};
}
getPerson = g3;
<span class="hljs-comment">//因为有可能要调用返回值上的方法</span>
getPerson().age.toFixed();
</code></pre>
            <h3 id="t918.5 函数的协变与逆变">8.5 函数的协变与逆变 <a
                    href="#t918.5%20%E5%87%BD%E6%95%B0%E7%9A%84%E5%8D%8F%E5%8F%98%E4%B8%8E%E9%80%86%E5%8F%98">
                    # </a></h3>
            <ul>
                <li>协变（Covariant）：只在同一个方向；</li>
                <li>逆变（Contravariant）：只在相反的方向；</li>
                <li>双向协变（Bivariant）：包括同一个方向和不同方向；</li>
                <li>
                    <p>不变（Invariant）：如果类型不完全相同，则它们是不兼容的。</p>
                </li>
                <li>
                    <p>A ≼ B 意味着 A 是 B 的子类型。</p>
                </li>
                <li>A → B 指的是以 A 为参数类型，以 B 为返回值类型的函数类型。</li>
                <li>
                    <p>x : A 意味着 x 的类型为 A</p>
                </li>
                <li>
                    <p>返回值类型是协变的，而参数类型是逆变的</p>
                </li>
                <li>返回值类型可以传子类,参数可以传父类</li>
                <li>参数逆变父类 返回值协变子类 搀你父,返鞋子</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span></span>{}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span></span>{
    public name:string = <span class="hljs-string">'Dog'</span>
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BlackDog</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Dog</span> </span>{
    public age: number = <span class="hljs-number">10</span>
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WhiteDog</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Dog</span> </span>{
    public home: string = <span class="hljs-string">'北京'</span>
}
<span class="hljs-keyword">let</span> animal: Animal;
<span class="hljs-keyword">let</span> blackDog: BlackDog;
<span class="hljs-keyword">let</span> whiteDog: WhiteDog;
type Callback = <span class="hljs-function">(<span class="hljs-params">dog: Dog</span>)=&gt;</span>Dog;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">exec</span>(<span class="hljs-params">callback:Callback</span>):<span class="hljs-title">void</span></span>{
    callback(whiteDog);
}
<span class="hljs-comment">//不行  callback(redDog);</span>
type ChildToChild = <span class="hljs-function">(<span class="hljs-params">blackDog: BlackDog</span>) =&gt;</span> BlackDog;
<span class="hljs-keyword">const</span> childToChild: ChildToChild = (blackDog: BlackDog): <span class="hljs-function"><span class="hljs-params">BlackDog</span> =&gt;</span> blackDog
exec(childToChild);

<span class="hljs-comment">//也不行,理由同上</span>
type ChildToParent = <span class="hljs-function">(<span class="hljs-params">blackDog: BlackDog</span>) =&gt;</span> Animal;
<span class="hljs-keyword">const</span> childToParent: ChildToParent = (blackDog: BlackDog): <span class="hljs-function"><span class="hljs-params">Animal</span> =&gt;</span> animal
exec(childToParent);

<span class="hljs-comment">//不行 因为有可能调用返回的Dog的方法</span>
type ParentToParent = <span class="hljs-function">(<span class="hljs-params">animal: Animal</span>) =&gt;</span> Animal;
<span class="hljs-keyword">const</span> parentToParent: ParentToParent = (animal: Animal): <span class="hljs-function"><span class="hljs-params">Animal</span> =&gt;</span> animal
exec(parentToParent);

<span class="hljs-comment">//可以,所有的狗都是动物,返回的不管什么狗都是狗</span>
type ParentToChild = <span class="hljs-function">(<span class="hljs-params">animal: Animal</span>) =&gt;</span> BlackDog;
<span class="hljs-keyword">const</span> parentToChild: ParentToChild = (animal: Animal): <span class="hljs-function"><span class="hljs-params">BlackDog</span> =&gt;</span> blackDog
exec(parentToChild);
<span class="hljs-comment">//(Animal → Greyhound) ≼ (Dog → Dog)</span>
<span class="hljs-comment">//返回值类型很容易理解：黑狗是狗的子类。但参数类型则是相反的：动物是狗的父类！</span>
</code></pre>
            <pre><code class="lang-js"><span class="hljs-comment">// string | number|boolean 是 string | number的父类型</span>
<span class="hljs-comment">// string是string|number的子类型</span>
type Callback2 = <span class="hljs-function">(<span class="hljs-params">a: string | number</span>) =&gt;</span> string | number;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">exec2</span>(<span class="hljs-params">callback: Callback2</span>):<span class="hljs-title">void</span></span>{
    callback(<span class="hljs-string">''</span>);
}
type ParentToChild2 = <span class="hljs-function">(<span class="hljs-params">a: string | number | boolean</span>) =&gt;</span> string;
<span class="hljs-keyword">const</span> parentToChild2: ParentToChild2 = (a: string | number | boolean): <span class="hljs-function"><span class="hljs-params">string</span> =&gt;</span> <span class="hljs-string">''</span>
exec2(parentToChild2);

type Callback3 = <span class="hljs-function">(<span class="hljs-params">a: string | number</span>) =&gt;</span> string | number;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">exec3</span>(<span class="hljs-params">callback: Callback2</span>): <span class="hljs-title">void</span> </span>{
    callback(<span class="hljs-string">''</span>);
}
type ParentToParent3 = <span class="hljs-function">(<span class="hljs-params">a: string</span>) =&gt;</span> string;
<span class="hljs-keyword">const</span> parentToParent3: ParentToParent3 = (a: string): <span class="hljs-function"><span class="hljs-params">string</span> =&gt;</span> <span class="hljs-string">''</span>
exec3(parentToChild3);
</code></pre>
            <ul>
                <li>在 TypeScript 中， 参数类型是双向协变的 ，也就是说既是协变又是逆变的，而这并不安全。但是现在你可以在 TypeScript 2.6 版本中通过
                    <code>--strictFunctionTypes</code> 或 <code>--strict</code> 标记来修复这个问题</li>
            </ul>
            <h3 id="t928.6 泛型的兼容性">8.6 泛型的兼容性 <a
                    href="#t928.6%20%E6%B3%9B%E5%9E%8B%E7%9A%84%E5%85%BC%E5%AE%B9%E6%80%A7">
                    # </a></h3>
            <ul>
                <li>泛型在判断兼容性的时候会先判断具体的类型,然后再进行兼容性判断</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-comment">//接口内容为空没用到泛型的时候是可以的</span>
<span class="hljs-comment">//1.接口内容为空没用到泛型的时候是可以的</span>
interface Empty&lt;T&gt;{}
<span class="hljs-keyword">let</span> x!:Empty&lt;string&gt;;
<span class="hljs-keyword">let</span> y!:Empty&lt;number&gt;;
x = y;

<span class="hljs-comment">//2.接口内容不为空的时候不可以</span>
interface NotEmpty&lt;T&gt;{
  <span class="hljs-attr">data</span>:T
}
<span class="hljs-keyword">let</span> x1!:NotEmpty&lt;string&gt;;
<span class="hljs-keyword">let</span> y1!:NotEmpty&lt;number&gt;;
x1 = y1;

<span class="hljs-comment">//实现原理如下,称判断具体的类型再判断兼容性</span>
interface NotEmptyString{
    <span class="hljs-attr">data</span>:string
}

interface NotEmptyNumber{
    <span class="hljs-attr">data</span>:number
}
<span class="hljs-keyword">let</span> xx2!:NotEmptyString;
<span class="hljs-keyword">let</span> yy2!:NotEmptyNumber;
xx2 = yy2;
</code></pre>
            <h3 id="t938.7 枚举的兼容性">8.7 枚举的兼容性 <a
                    href="#t938.7%20%E6%9E%9A%E4%B8%BE%E7%9A%84%E5%85%BC%E5%AE%B9%E6%80%A7">
                    # </a></h3>
            <ul>
                <li>枚举类型与数字类型兼容，并且数字类型与枚举类型兼容</li>
                <li>不同枚举类型之间是不兼容的</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-comment">//数字可以赋给枚举</span>
enum Colors {Red,Yellow}
<span class="hljs-keyword">let</span> c:Colors;
c = Colors.Red;
c = <span class="hljs-number">1</span>;
c = <span class="hljs-string">'1'</span>;

<span class="hljs-comment">//枚举值可以赋给数字</span>
<span class="hljs-keyword">let</span> n:number;
n = <span class="hljs-number">1</span>;
n = Colors.Red;
</code></pre>
            <h2 id="t949.类型保护">9.类型保护 <a href="#t949.%E7%B1%BB%E5%9E%8B%E4%BF%9D%E6%8A%A4">
                    # </a></h2>
            <ul>
                <li>类型保护就是一些表达式，他们在编译的时候就能通过类型信息确保某个作用域内变量的类型</li>
                <li>类型保护就是能够通过关键字判断出分支中的类型</li>
            </ul>
            <h3 id="t959.1 typeof 类型保护">9.1 typeof 类型保护 <a
                    href="#t959.1%20typeof%20%E7%B1%BB%E5%9E%8B%E4%BF%9D%E6%8A%A4">
                    # </a></h3>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">double</span>(<span class="hljs-params">input: string | number | boolean</span>) </span>{
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> input === <span class="hljs-string">'string'</span>) {
        <span class="hljs-keyword">return</span> input + input;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> input === <span class="hljs-string">'number'</span>) {
            <span class="hljs-keyword">return</span> input * <span class="hljs-number">2</span>;
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> !input;
        }
    }
}
</code></pre>
            <h3 id="t969.2 instanceof类型保护">9.2 instanceof类型保护 <a
                    href="#t969.2%20instanceof%E7%B1%BB%E5%9E%8B%E4%BF%9D%E6%8A%A4">
                    # </a></h3>
            <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span> </span>{
    name!: string;
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Bird</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span> </span>{
    swing!: number
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getName</span>(<span class="hljs-params">animal: Animal</span>) </span>{
    <span class="hljs-keyword">if</span> (animal <span class="hljs-keyword">instanceof</span> Bird) {
        <span class="hljs-built_in">console</span>.log(animal.swing);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">console</span>.log(animal.name);
    }
}
</code></pre>
            <h3 id="t979.3 null保护">9.3 null保护 <a href="#t979.3%20null%E4%BF%9D%E6%8A%A4">
                    # </a></h3>
            <ul>
                <li>如果开启了<code>strictNullChecks</code>选项，那么对于可能为null的变量不能调用它上面的方法和属性</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getFirstLetter</span>(<span class="hljs-params">s: string | null</span>) </span>{
    <span class="hljs-comment">//第一种方式是加上null判断</span>
    <span class="hljs-keyword">if</span> (s == <span class="hljs-literal">null</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-string">''</span>;
    }
    <span class="hljs-comment">//第二种处理是增加一个或的处理</span>
    s = s || <span class="hljs-string">''</span>;
    <span class="hljs-keyword">return</span> s.charAt(<span class="hljs-number">0</span>);
}
<span class="hljs-comment">//它并不能处理一些复杂的判断，需要加非空断言操作符</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getFirstLetter2</span>(<span class="hljs-params">s: string | null</span>) </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">log</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-built_in">console</span>.log(s!.trim());
    }
    s = s || <span class="hljs-string">''</span>;
    log();
    <span class="hljs-keyword">return</span> s.charAt(<span class="hljs-number">0</span>);
}
</code></pre>
            <h3 id="t989.4 链判断运算符">9.4 链判断运算符 <a
                    href="#t989.4%20%E9%93%BE%E5%88%A4%E6%96%AD%E8%BF%90%E7%AE%97%E7%AC%A6">
                    # </a></h3>
            <ul>
                <li>链判断运算符是一种先检查属性是否存在，再尝试访问该属性的运算符，其符号为 ?.</li>
                <li>如果运算符左侧的操作数 ?. 计算为 undefined 或 null，则表达式求值为 undefined 。否则，正常触发目标属性访问，方法或函数调用。</li>
            </ul>
            <pre><code class="lang-js">a?.b; <span class="hljs-comment">//如果a是null/undefined,那么返回undefined，否则返回a.b的值.</span>
a == <span class="hljs-literal">null</span> ? <span class="hljs-literal">undefined</span> : a.b;

a?.[x]; <span class="hljs-comment">//如果a是null/undefined,那么返回undefined，否则返回a[x]的值</span>
a == <span class="hljs-literal">null</span> ? <span class="hljs-literal">undefined</span> : a[x];

a?.b(); <span class="hljs-comment">// 如果a是null/undefined,那么返回undefined</span>
a == <span class="hljs-literal">null</span> ? <span class="hljs-literal">undefined</span> : a.b(); <span class="hljs-comment">//如果a.b不函数的话抛类型错误异常,否则计算a.b()的结果</span>

a?.(); <span class="hljs-comment">//如果a是null/undefined,那么返回undefined</span>
a == <span class="hljs-literal">null</span> ? <span class="hljs-literal">undefined</span> : a(); <span class="hljs-comment">//如果A不是函数会抛出类型错误</span>
<span class="hljs-comment">//否则 调用a这个函数</span>
</code></pre>
            <blockquote>
                <p> 链判断运算符 还处于 stage1 阶段,TS 也暂时不支持</p>
            </blockquote>
            <h3 id="t999.5 可辨识的联合类型">9.5 可辨识的联合类型 <a
                    href="#t999.5%20%E5%8F%AF%E8%BE%A8%E8%AF%86%E7%9A%84%E8%81%94%E5%90%88%E7%B1%BB%E5%9E%8B">
                    # </a></h3>
            <ul>
                <li>就是利用联合类型中的共有字段进行类型保护的一种技巧</li>
                <li>相同字段的不同取值就是可辨识</li>
            </ul>
            <pre><code class="lang-js">interface WarningButton{
  <span class="hljs-attr">class</span>:<span class="hljs-string">'warning'</span>,
  <span class="hljs-attr">text1</span>:<span class="hljs-string">'修改'</span>
}
interface DangerButton{
  <span class="hljs-attr">class</span>:<span class="hljs-string">'danger'</span>,
  <span class="hljs-attr">text2</span>:<span class="hljs-string">'删除'</span>
}
type Button = WarningButton|DangerButton;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getButton</span>(<span class="hljs-params">button:Button</span>)</span>{
 <span class="hljs-keyword">if</span>(button.class==<span class="hljs-string">'warning'</span>){
  <span class="hljs-built_in">console</span>.log(button.text1);
 }
 <span class="hljs-keyword">if</span>(button.class==<span class="hljs-string">'danger'</span>){
  <span class="hljs-built_in">console</span>.log(button.text2);
 }
}
</code></pre>
            <p>类型字面量+可辨识联合类型</p>
            <pre><code class="lang-js">interface User {
    <span class="hljs-attr">username</span>: string
}
type Action = {
    <span class="hljs-attr">type</span>:<span class="hljs-string">'add'</span>,
    <span class="hljs-attr">payload</span>:User
} | {
    <span class="hljs-attr">type</span>: <span class="hljs-string">'delete'</span>
    <span class="hljs-attr">payload</span>: number
}
<span class="hljs-keyword">const</span> UserReducer = <span class="hljs-function">(<span class="hljs-params">action: Action</span>) =&gt;</span> {
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">"add"</span>:
      <span class="hljs-keyword">let</span> user: User = action.payload;
      <span class="hljs-keyword">break</span>;
    <span class="hljs-keyword">case</span> <span class="hljs-string">"delete"</span>:
      <span class="hljs-keyword">let</span> id: number = action.payload;
      <span class="hljs-keyword">break</span>;
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">break</span>;
  }
};

</code></pre>
            <h3 id="t1009.6 in操作符">9.6 in操作符 <a href="#t1009.6%20in%E6%93%8D%E4%BD%9C%E7%AC%A6">
                    # </a></h3>
            <ul>
                <li>in 运算符可以被用于参数类型的判断</li>
            </ul>
            <pre><code class="lang-js">interface Bird {
    <span class="hljs-attr">swing</span>: number;
}

interface Dog {
    <span class="hljs-attr">leg</span>: number;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getNumber</span>(<span class="hljs-params">x: Bird | Dog</span>) </span>{
    <span class="hljs-keyword">if</span> (<span class="hljs-string">"swing"</span> <span class="hljs-keyword">in</span> x) {
      <span class="hljs-keyword">return</span> x.swing;
    }
    <span class="hljs-keyword">return</span> x.leg;
}
</code></pre>
            <h3 id="t1019.7 自定义的类型保护">9.7 自定义的类型保护 <a
                    href="#t1019.7%20%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%E7%B1%BB%E5%9E%8B%E4%BF%9D%E6%8A%A4">
                    # </a></h3>
            <ul>
                <li>TypeScript 里的类型保护本质上就是一些表达式，它们会在运行时检查类型信息，以确保在某个作用域里的类型是符合预期的</li>
                <li><code>type is Type1Class</code>就是类型谓词</li>
                <li>谓词为 <code>parameterName is Type</code>这种形式,<code>parameterName</code>必须是来自于当前函数签名里的一个参数名</li>
                <li>每当使用一些变量调用<code>isType1</code>时，如果原始类型兼容，<code>TypeScript</code>会将该变量缩小到该特定类型</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isType1</span>(<span class="hljs-params">type: Type1Class | Type2Class</span>): <span class="hljs-title">type</span> <span class="hljs-title">is</span> <span class="hljs-title">Type1Class</span> </span>{
    <span class="hljs-keyword">return</span> (<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Type1Class</span>&gt;</span>type).func1 !== undefined;
}
</span></code></pre>
            <pre><code class="lang-js">interface Bird {
  <span class="hljs-attr">swing</span>: number;
}

interface Dog {
  <span class="hljs-attr">leg</span>: number;
}

<span class="hljs-comment">//没有相同字段可以定义一个类型保护函数</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isBird</span>(<span class="hljs-params">x:Bird|Dog</span>): <span class="hljs-title">x</span> <span class="hljs-title">is</span> <span class="hljs-title">Bird</span></span>{
  <span class="hljs-keyword">return</span> (<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Bird</span>&gt;</span>x).swing == 2;
  //return (x as Bird).swing == 2;
}

function getAnimal(x: Bird | Dog) {
  if (isBird(x)) {
    return x.swing;
  }
  return x.leg;
}
</span></code></pre>
            <h3 id="t1029.8 unknown">9.8 unknown <a href="#t1029.8%20unknown"> # </a></h3>
            <ul>
                <li>TypeScript 3.0 引入了新的unknown 类型，它是 any 类型对应的安全类型</li>
                <li>unknown 和 any 的主要区别是 unknown 类型会更加严格：在对 unknown 类型的值执行大多数操作之前，我们必须进行某种形式的检查。而在对 any
                    类型的值执行操作之前，我们不必进行任何检查</li>
            </ul>
            <h4 id="t1039.8.1 any 类型">9.8.1 any 类型 <a href="#t1039.8.1%20any%20%E7%B1%BB%E5%9E%8B">
                    # </a></h4>
            <ul>
                <li>在 TypeScript 中，任何类型都可以被归为 any 类型。这让 any 类型成为了类型系统的 顶级类型 (也被称作 全局超级类型)。</li>
                <li>TypeScript允许我们对 any 类型的值执行任何操作，而无需事先执行任何形式的检查</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> value: any;

value = <span class="hljs-literal">true</span>;             <span class="hljs-comment">// OK</span>
value = <span class="hljs-number">42</span>;               <span class="hljs-comment">// OK</span>
value = <span class="hljs-string">"Hello World"</span>;    <span class="hljs-comment">// OK</span>
value = [];               <span class="hljs-comment">// OK</span>
value = {};               <span class="hljs-comment">// OK</span>
value = <span class="hljs-built_in">Math</span>.random;      <span class="hljs-comment">// OK</span>
value = <span class="hljs-literal">null</span>;             <span class="hljs-comment">// OK</span>
value = <span class="hljs-literal">undefined</span>;        <span class="hljs-comment">// OK</span>


<span class="hljs-keyword">let</span> value: any;
value.foo.bar;  <span class="hljs-comment">// OK</span>
value.trim();   <span class="hljs-comment">// OK</span>
value();        <span class="hljs-comment">// OK</span>
<span class="hljs-keyword">new</span> value();    <span class="hljs-comment">// OK</span>

</code></pre>
            <h4 id="t1049.8.2 unknown 类型">9.8.2 unknown 类型 <a href="#t1049.8.2%20unknown%20%E7%B1%BB%E5%9E%8B">
                    # </a></h4>
            <ul>
                <li>
                    <p>就像所有类型都可以被归为 any，所有类型也都可以被归为 unknown。这使得 unknown 成为 TypeScript 类型系统的另一种顶级类型（另一种是 any）</p>
                </li>
                <li>
                    <p>任何类型都可以赋值给<code>unknown</code>类型</p>
                </li>
            </ul>
            <pre><code class="lang-js">
<span class="hljs-keyword">let</span> value: unknown;

value = <span class="hljs-literal">true</span>;             <span class="hljs-comment">// OK</span>
value = <span class="hljs-number">42</span>;               <span class="hljs-comment">// OK</span>
value = <span class="hljs-string">"Hello World"</span>;    <span class="hljs-comment">// OK</span>
value = [];               <span class="hljs-comment">// OK</span>
value = {};               <span class="hljs-comment">// OK</span>
value = <span class="hljs-built_in">Math</span>.random;      <span class="hljs-comment">// OK</span>
value = <span class="hljs-literal">null</span>;             <span class="hljs-comment">// OK</span>
value = <span class="hljs-literal">undefined</span>;        <span class="hljs-comment">// OK</span>
value = <span class="hljs-keyword">new</span> <span class="hljs-built_in">TypeError</span>();  <span class="hljs-comment">// OK</span>

</code></pre>
            <ul>
                <li><code>unknown</code>类型只能被赋值给<code>any</code>类型和<code>unknown</code>类型本身</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> value: unknown;
<span class="hljs-keyword">let</span> value1: unknown = value;   <span class="hljs-comment">// OK</span>
<span class="hljs-keyword">let</span> value2: any = value;       <span class="hljs-comment">// OK</span>
<span class="hljs-keyword">let</span> value3: boolean = value;   <span class="hljs-comment">// Error</span>
<span class="hljs-keyword">let</span> value4: number = value;    <span class="hljs-comment">// Error</span>
<span class="hljs-keyword">let</span> value5: string = value;    <span class="hljs-comment">// Error</span>
<span class="hljs-keyword">let</span> value6: object = value;    <span class="hljs-comment">// Error</span>
<span class="hljs-keyword">let</span> value7: any[] = value;     <span class="hljs-comment">// Error</span>
<span class="hljs-keyword">let</span> value8: <span class="hljs-built_in">Function</span> = value;  <span class="hljs-comment">// Error</span>
</code></pre>
            <h4 id="t1059.8.3 缩小 unknown 类型范围">9.8.3 缩小 unknown 类型范围 <a
                    href="#t1059.8.3%20%E7%BC%A9%E5%B0%8F%20unknown%20%E7%B1%BB%E5%9E%8B%E8%8C%83%E5%9B%B4">
                    # </a></h4>
            <ul>
                <li>如果没有类型断言或类型细化时，不能在<code>unknown</code>上面进行任何操作</li>
                <li>typeof</li>
                <li>instanceof</li>
                <li>自定义类型保护函数</li>
                <li>可以对 unknown 类型使用类型断言</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">const</span> value: unknown = <span class="hljs-string">"Hello World"</span>;
<span class="hljs-keyword">const</span> someString: string = value <span class="hljs-keyword">as</span> string;
</code></pre>
            <h3 id="t1069.8.4 联合类型中的 unknown 类型">9.8.4 联合类型中的 unknown 类型 <a
                    href="#t1069.8.4%20%E8%81%94%E5%90%88%E7%B1%BB%E5%9E%8B%E4%B8%AD%E7%9A%84%20unknown%20%E7%B1%BB%E5%9E%8B">
                    # </a></h3>
            <ul>
                <li>在联合类型中，unknown 类型会吸收任何类型。这就意味着如果任一组成类型是 unknown，联合类型也会相当于 unknown：
                    <pre><code class="lang-js">type UnionType1 = unknown | <span class="hljs-literal">null</span>;       <span class="hljs-comment">// unknown</span>
type UnionType2 = unknown | <span class="hljs-literal">undefined</span>;  <span class="hljs-comment">// unknown</span>
type UnionType3 = unknown | string;     <span class="hljs-comment">// unknown</span>
type UnionType4 = unknown | number[];   <span class="hljs-comment">// unknown</span>
</code></pre>
                </li>
            </ul>
            <h3 id="t1079.8.5  交叉类型中的 unknown 类型">9.8.5 交叉类型中的 unknown 类型 <a
                    href="#t1079.8.5%20%20%E4%BA%A4%E5%8F%89%E7%B1%BB%E5%9E%8B%E4%B8%AD%E7%9A%84%20unknown%20%E7%B1%BB%E5%9E%8B">
                    # </a></h3>
            <ul>
                <li>在交叉类型中，任何类型都可以吸收 unknown 类型。这意味着将任何类型与 unknown 相交不会改变结果类型</li>
            </ul>
            <pre><code class="lang-js">type IntersectionType1 = unknown &amp; <span class="hljs-literal">null</span>;       <span class="hljs-comment">// null</span>
type IntersectionType2 = unknown &amp; <span class="hljs-literal">undefined</span>;  <span class="hljs-comment">// undefined</span>
type IntersectionType3 = unknown &amp; string;     <span class="hljs-comment">// string</span>
type IntersectionType4 = unknown &amp; number[];   <span class="hljs-comment">// number[]</span>
type IntersectionType5 = unknown &amp; any;        <span class="hljs-comment">// any</span>
</code></pre>
            <h3 id="t1089.8.6 never是unknown的子类型">9.8.6 never是unknown的子类型 <a
                    href="#t1089.8.6%20never%E6%98%AFunknown%E7%9A%84%E5%AD%90%E7%B1%BB%E5%9E%8B">
                    # </a></h3>
            <pre><code class="lang-js">type isNever = never extends unknown ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span>;
</code></pre>
            <h3 id="t1099.8.7 keyof unknown 等于never">9.8.7 keyof unknown 等于never <a
                    href="#t1099.8.7%20keyof%20unknown%20%E7%AD%89%E4%BA%8Enever">
                    # </a></h3>
            <pre><code class="lang-js">type key = keyof unknown;
</code></pre>
            <h3 id="t1109.8.8 只能对unknown进行等或不等操作，不能进行其它操作">9.8.8 只能对unknown进行等或不等操作，不能进行其它操作 <a
                    href="#t1109.8.8%20%E5%8F%AA%E8%83%BD%E5%AF%B9unknown%E8%BF%9B%E8%A1%8C%E7%AD%89%E6%88%96%E4%B8%8D%E7%AD%89%E6%93%8D%E4%BD%9C%EF%BC%8C%E4%B8%8D%E8%83%BD%E8%BF%9B%E8%A1%8C%E5%85%B6%E5%AE%83%E6%93%8D%E4%BD%9C">
                    # </a></h3>
            <pre><code class="lang-js">un1===un2;
un1!==un2;
un1 += un2;
</code></pre>
            <h3 id="t1119.8.9 不能做任何操作">9.8.9 不能做任何操作 <a
                    href="#t1119.8.9%20%E4%B8%8D%E8%83%BD%E5%81%9A%E4%BB%BB%E4%BD%95%E6%93%8D%E4%BD%9C">
                    # </a></h3>
            <ul>
                <li>不能访问属性</li>
                <li>不能作为函数调用</li>
                <li>不能当作类的构造函数不能创建实例</li>
            </ul>
            <pre><code class="lang-js">un.name
un();
<span class="hljs-keyword">new</span> un();
</code></pre>
            <h3 id="t1129.8.10 映射属性">9.8.10 映射属性 <a href="#t1129.8.10%20%E6%98%A0%E5%B0%84%E5%B1%9E%E6%80%A7">
                    # </a></h3>
            <ul>
                <li>如果映射类型遍历的时候是unknown,不会映射属性
                    <pre><code class="lang-js">type getType&lt;T&gt; = {
  [P <span class="hljs-keyword">in</span> keyof T]:number
}
type t = getType&lt;unknown&gt;;
</code></pre>
                </li>
            </ul>
            <h2 id="t11310. 类型变换">10. 类型变换 <a href="#t11310.%20%E7%B1%BB%E5%9E%8B%E5%8F%98%E6%8D%A2">
                    # </a></h2>
            <h3 id="t11410.1 类型推断">10.1 类型推断 <a href="#t11410.1%20%E7%B1%BB%E5%9E%8B%E6%8E%A8%E6%96%AD">
                    # </a></h3>
            <ul>
                <li>TypeScript 能根据一些简单的规则推断变量的类型</li>
            </ul>
            <h4 id="t11510.1.1 从右向左">10.1.1 从右向左 <a href="#t11510.1.1%20%E4%BB%8E%E5%8F%B3%E5%90%91%E5%B7%A6">
                    # </a></h4>
            <ul>
                <li>变量的类型可以由定义推断</li>
                <li>这是一个从右向左流动类型的示例</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">let</span> foo = <span class="hljs-number">1</span>; <span class="hljs-comment">// foo 是 'number'</span>
<span class="hljs-keyword">let</span> bar = <span class="hljs-string">'zhufeng'</span>; <span class="hljs-comment">// bar 是 'string'</span>
<span class="hljs-comment">//foo = bar; // Error: 不能将 'string' 赋值给 `number`</span>
</code></pre>
            <h4 id="t11610.1.2 底部流出">10.1.2 底部流出 <a href="#t11610.1.2%20%E5%BA%95%E9%83%A8%E6%B5%81%E5%87%BA">
                    # </a></h4>
            <ul>
                <li>返回类型能被 <code>return</code> 语句推断</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">add</span>(<span class="hljs-params">a: number, b: number</span>) </span>{
    <span class="hljs-keyword">return</span> a + b;
}
<span class="hljs-keyword">let</span> c = add(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>);
</code></pre>
            <h4 id="t11710.1.3 从左向右">10.1.3 从左向右 <a href="#t11710.1.3%20%E4%BB%8E%E5%B7%A6%E5%90%91%E5%8F%B3">
                    # </a></h4>
            <ul>
                <li>函数参数类型/返回值类型也能通过赋值来推断</li>
            </ul>
            <pre><code class="lang-js">type Sum = <span class="hljs-function">(<span class="hljs-params">a: number, b: number</span>) =&gt;</span> number;
<span class="hljs-keyword">let</span> sum: Sum = <span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> {
    a=<span class="hljs-string">'zhufeng'</span>;
    <span class="hljs-keyword">return</span> a + b;
};
</code></pre>
            <h4 id="t11810.1.4 结构化">10.1.4 结构化 <a href="#t11810.1.4%20%E7%BB%93%E6%9E%84%E5%8C%96">
                    # </a></h4>
            <ul>
                <li>推断规则也适用于结构化的存在(对象字面量)</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">const</span> person = {
    <span class="hljs-attr">name</span>: <span class="hljs-string">'zhufeng'</span>,
    <span class="hljs-attr">age</span>: <span class="hljs-number">11</span>
};
<span class="hljs-keyword">let</span> name =person.name;
<span class="hljs-keyword">let</span> age =person.age;
age = <span class="hljs-string">'hello'</span>; <span class="hljs-comment">// Error：不能把 'string' 类型赋值给 'number' 类型</span>
</code></pre>
            <h4 id="t11910.1.5 解构">10.1.5 解构 <a href="#t11910.1.5%20%E8%A7%A3%E6%9E%84">
                    # </a></h4>
            <ul>
                <li>推断规则也适用于解构</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">const</span> person = {
    <span class="hljs-attr">name</span>: <span class="hljs-string">'zhufeng'</span>,
    <span class="hljs-attr">age</span>: <span class="hljs-number">11</span>
};
<span class="hljs-keyword">let</span> { name,age } = person;

age = <span class="hljs-string">'hello'</span>; <span class="hljs-comment">// Error：不能把 'string' 类型赋值给 'number' 类型</span>

<span class="hljs-comment">//数组也一样</span>
<span class="hljs-keyword">const</span> numbers = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>];
numbers[<span class="hljs-number">0</span>] = <span class="hljs-string">'hello'</span>; <span class="hljs-comment">// Error：不能把 'string' 类型赋值给 'number' 类型</span>
</code></pre>
            <h4 id="t12010.1.5 DefaultProps">10.1.5 DefaultProps <a href="#t12010.1.5%20DefaultProps"> #
                </a></h4>
            <pre><code class="lang-js">
interface DefaultProps{
    name?:string;
    age?:number;
}
<span class="hljs-keyword">let</span> defaultProps: DefaultProps = {
   <span class="hljs-attr">name</span>:<span class="hljs-string">'zhufeng'</span>,
   <span class="hljs-attr">age</span>:<span class="hljs-number">10</span>
}

<span class="hljs-keyword">let</span> props = {
    ...defaultProps,
    <span class="hljs-attr">home</span>:<span class="hljs-string">'北京'</span>
}
type Props = <span class="hljs-keyword">typeof</span> props;
</code></pre>
            <h4 id="t12110.1.6 小心使用返回值">10.1.6 小心使用返回值 <a
                    href="#t12110.1.6%20%E5%B0%8F%E5%BF%83%E4%BD%BF%E7%94%A8%E8%BF%94%E5%9B%9E%E5%80%BC">
                    # </a></h4>
            <ul>
                <li>尽管 TypeScript 一般情况下能推断函数的返回值，但是它可能并不是你想要的</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addOne</span>(<span class="hljs-params">a:any</span>) </span>{
    <span class="hljs-keyword">return</span> a + <span class="hljs-number">1</span>;
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sum</span>(<span class="hljs-params">a: number, b: number</span>) </span>{
    <span class="hljs-keyword">return</span> a + addOne(b);
}

type Ret = ReturnType&lt;<span class="hljs-keyword">typeof</span> sum&gt;;
</code></pre>
            <h3 id="t12210.1 交叉类型">10.1 交叉类型 <a href="#t12210.1%20%E4%BA%A4%E5%8F%89%E7%B1%BB%E5%9E%8B">
                    # </a></h3>
            <ul>
                <li>交叉类型(Intersection Types)是将多个类型合并为一个类型</li>
                <li>这让我们可以把现有的多种类型叠加到一起成为一种类型，它包含了所需的所有类型的特性</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-comment">//TypeScript 交叉类型是将多个类型合并为一个类型</span>
<span class="hljs-comment">//这让我们可以把现有的多种类型叠加到一起成为一种类型</span>
<span class="hljs-comment">//它包含了所需的所有类型的特性</span>

<span class="hljs-keyword">export</span> {}
<span class="hljs-comment">//接口的交叉</span>
interface Bird {
    <span class="hljs-attr">name</span>: string,
    fly(): <span class="hljs-keyword">void</span>
}
interface Person {
    <span class="hljs-attr">name</span>: string,
    talk(): <span class="hljs-keyword">void</span>
}
type BirdPerson = Bird &amp; Person;
<span class="hljs-keyword">let</span> p: BirdPerson = { <span class="hljs-attr">name</span>: <span class="hljs-string">'zhufeng'</span>, fly() { }, talk() { } };
p.fly;
p.name
p.talk;
</code></pre>
            <pre><code class="lang-js">interface X {
    <span class="hljs-attr">a</span>: string;
    b: string;
}

interface Y {
    <span class="hljs-attr">a</span>: number;
    c: string
}

type XY = X &amp; Y;
type YX = Y &amp; X;
<span class="hljs-comment">//c = string &amp; number</span>
<span class="hljs-comment">//let p1: XY={a:'',b:'',c:''};</span>
</code></pre>
            <p>联合类型的交叉类型</p>
            <pre><code class="lang-js">type Ta = string | number;
type Tb = number | boolean;
type Tc = Ta &amp; Tb;
</code></pre>
            <p><code>mixin</code>混入模式可以让你从两个对象中创建一个新对象，新对象会拥有着两个对象所有的功能</p>
            <pre><code class="lang-js">interface AnyObject {
    [prop: string]: any;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mixin</span>&lt;<span class="hljs-title">T</span> <span class="hljs-title">extends</span> <span class="hljs-title">AnyObject</span>, <span class="hljs-title">U</span> <span class="hljs-title">extends</span> <span class="hljs-title">AnyObject</span>&gt;(<span class="hljs-params">one: T,two: U</span>): <span class="hljs-title">T</span> &amp; <span class="hljs-title">U</span> </span>{
    <span class="hljs-keyword">const</span> result = &lt;T &amp; U&gt;{};
    for (let key in one) {
        (&lt;T&gt;result)[key] = one[key];
    }
    for (let key in two) {
        (&lt;U&gt;result)[key] = two[key];
    }
    return result;
}

const x = mixin({ name: "zhufeng" }, { age: 11 });
console.log(x.name, x.age);
</code></pre>
            <h3 id="t12310.2 typeof">10.2 typeof <a href="#t12310.2%20typeof"> # </a></h3>
            <ul>
                <li>可以获取一个变量的类型 </li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-comment">//先定义类型，再定义变量</span>
type People = {
    <span class="hljs-attr">name</span>:string,
    <span class="hljs-attr">age</span>:number,
    <span class="hljs-attr">gender</span>:string
}
<span class="hljs-keyword">let</span> p1:People = {
    <span class="hljs-attr">name</span>:<span class="hljs-string">'zhufeng'</span>,
    <span class="hljs-attr">age</span>:<span class="hljs-number">10</span>,
    <span class="hljs-attr">gender</span>:<span class="hljs-string">'male'</span>
}
</code></pre>
            <pre><code class="lang-js"><span class="hljs-comment">//先定义变量，再定义类型</span>
<span class="hljs-keyword">let</span> p1 = {
    <span class="hljs-attr">name</span>:<span class="hljs-string">'zhufeng'</span>,
    <span class="hljs-attr">age</span>:<span class="hljs-number">10</span>,
    <span class="hljs-attr">gender</span>:<span class="hljs-string">'male'</span>
}
type People = <span class="hljs-keyword">typeof</span> p1;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getName</span>(<span class="hljs-params">p:People</span>):<span class="hljs-title">string</span></span>{
    <span class="hljs-keyword">return</span> p.name;
}
getName(p1);
</code></pre>
            <h3 id="t12410.3 索引访问操作符">10.3 索引访问操作符 <a
                    href="#t12410.3%20%E7%B4%A2%E5%BC%95%E8%AE%BF%E9%97%AE%E6%93%8D%E4%BD%9C%E7%AC%A6">
                    # </a></h3>
            <ul>
                <li>可以通过[]获取一个类型的子类型</li>
            </ul>
            <pre><code class="lang-js">interface Person{
    <span class="hljs-attr">name</span>:string;
    age:number;
    job:{
        <span class="hljs-attr">name</span>:string
    };
    interests:{<span class="hljs-attr">name</span>:string,<span class="hljs-attr">level</span>:number}[]
}
<span class="hljs-keyword">let</span> FrontEndJob:Person[<span class="hljs-string">'job'</span>] = {
    <span class="hljs-attr">name</span>:<span class="hljs-string">'前端工程师'</span>
}
<span class="hljs-keyword">let</span> interestLevel:Person[<span class="hljs-string">'interests'</span>][<span class="hljs-number">0</span>][<span class="hljs-string">'level'</span>] = <span class="hljs-number">2</span>;
</code></pre>
            <h3 id="t12510.4 keyof">10.4 keyof <a href="#t12510.4%20keyof"> # </a></h3>
            <ul>
                <li>索引类型查询操作符</li>
            </ul>
            <pre><code class="lang-js">interface Person{
  <span class="hljs-attr">name</span>:string;
  age:number;
  gender:<span class="hljs-string">'male'</span>|<span class="hljs-string">'female'</span>;
}
<span class="hljs-comment">//type PersonKey = 'name'|'age'|'gender';</span>
type PersonKey = keyof Person;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getValueByKey</span>(<span class="hljs-params">p:Person,key:PersonKey</span>)</span>{
  <span class="hljs-keyword">return</span> p[key];
}
<span class="hljs-keyword">let</span> val = getValueByKey({<span class="hljs-attr">name</span>:<span class="hljs-string">'zhufeng'</span>,<span class="hljs-attr">age</span>:<span class="hljs-number">10</span>,<span class="hljs-attr">gender</span>:<span class="hljs-string">'male'</span>},<span class="hljs-string">'name'</span>);
<span class="hljs-built_in">console</span>.log(val);
</code></pre>
            <h3 id="t12610.5 映射类型">10.5 映射类型 <a href="#t12610.5%20%E6%98%A0%E5%B0%84%E7%B1%BB%E5%9E%8B">
                    # </a></h3>
            <ul>
                <li>在定义的时候用in操作符去批量定义类型中的属性</li>
            </ul>
            <pre><code class="lang-js">interface Person{
  <span class="hljs-attr">name</span>:string;
  age:number;
  gender:<span class="hljs-string">'male'</span>|<span class="hljs-string">'female'</span>;
}
<span class="hljs-comment">//批量把一个接口中的属性都变成可选的</span>
type PartPerson = {
  [Key <span class="hljs-keyword">in</span> keyof Person]?:Person[Key]
}

<span class="hljs-keyword">let</span> p1:PartPerson={};
<span class="hljs-comment">//也可以使用泛型</span>
type Part&lt;T&gt; = {
  [key <span class="hljs-keyword">in</span> keyof T]?:T[key]
}
<span class="hljs-keyword">let</span> p2:Part&lt;Person&gt;={};
</code></pre>
            <ul>
                <li>通过key的数组获取值的数组
                    <pre><code class="lang-js">function pick&lt;T, K extends keyof T&gt;(o: T, names: K[]): T[K][] {
  return names.map((n) =&gt; o[n]);
}
let user = { id: 1, name: 'zhufeng' };
type User = typeof user;
const res = pick&lt;User, keyof User&gt;(user, ["id", "name"]);
console.log(res);
</code></pre>
                </li>
            </ul>
            <h3 id="t12710.6 条件类型">10.6 条件类型 <a href="#t12710.6%20%E6%9D%A1%E4%BB%B6%E7%B1%BB%E5%9E%8B">
                    # </a></h3>
            <ul>
                <li>在定义泛型的时候能够添加进逻辑分支，以后泛型更加灵活</li>
            </ul>
            <h4 id="t12810.6.1 定义条件类型">10.6.1 定义条件类型 <a
                    href="#t12810.6.1%20%E5%AE%9A%E4%B9%89%E6%9D%A1%E4%BB%B6%E7%B1%BB%E5%9E%8B">
                    # </a></h4>
            <pre><code class="lang-js">interface Fish {
    <span class="hljs-attr">name</span>: string
}
interface Water {
    <span class="hljs-attr">name</span>: string
}
interface Bird {
    <span class="hljs-attr">name</span>: string
}
interface Sky {
    <span class="hljs-attr">name</span>: string
}
<span class="hljs-comment">//若 T 能够赋值给 Fish，那么类型是 Water,否则为 Sky</span>
type Condition&lt;T&gt; = T extends Fish ? Water : Sky;
<span class="hljs-keyword">let</span> condition: Condition&lt;Fish&gt; = { <span class="hljs-attr">name</span>: <span class="hljs-string">'水'</span> };
</code></pre>
            <h4 id="t12910.6.2 条件类型的分发">10.6.2 条件类型的分发 <a
                    href="#t12910.6.2%20%E6%9D%A1%E4%BB%B6%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%88%86%E5%8F%91">
                    # </a></h4>
            <pre><code class="lang-js">interface Fish {
    <span class="hljs-attr">fish</span>: string
}
interface Water {
    <span class="hljs-attr">water</span>: string
}
interface Bird {
    <span class="hljs-attr">bird</span>: string
}
interface Sky {
    <span class="hljs-attr">sky</span>: string
}
<span class="hljs-comment">//naked type</span>
type Condition&lt;T&gt; = T extends Fish ? Water : Sky;

<span class="hljs-comment">//(Fish extends Fish ? Water : Sky) | (Bird extends Fish ? Water : Sky)</span>
<span class="hljs-comment">// Water|Sky</span>
<span class="hljs-keyword">let</span> condition1: Condition&lt;Fish | Bird&gt; = { <span class="hljs-attr">water</span>: <span class="hljs-string">'水'</span> };
<span class="hljs-keyword">let</span> condition2: Condition&lt;Fish | Bird&gt; = { <span class="hljs-attr">sky</span>: <span class="hljs-string">'天空'</span> };
</code></pre>
            <ul>
                <li>条件类型有一个特性,就是「分布式有条件类型」,但是分布式有条件类型是有前提的,条件类型里待检查的类型必须是naked type parameter</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-comment">//none naked type</span>
<span class="hljs-comment">//type Condition&lt;T&gt; = [T] extends [Fish] ? Water : Sky;</span>
</code></pre>
            <ul>
                <li>找出T类型中U不包含的部分</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-comment">//never会被自动过滤</span>
type Diff&lt;T, U&gt; = T extends U ? never : T;

type R = Diff&lt;<span class="hljs-string">"a"</span> | <span class="hljs-string">"b"</span> | <span class="hljs-string">"c"</span> | <span class="hljs-string">"d"</span>, <span class="hljs-string">"a"</span> | <span class="hljs-string">"c"</span> | <span class="hljs-string">"f"</span>&gt;;  <span class="hljs-comment">// "b" | "d"</span>

type Filter&lt;T, U&gt; = T extends U ? T : never;
type R1 = Filter&lt;string | number | boolean, number&gt;;
</code></pre>
            <h4 id="t13010.6.3 内置条件类型">10.6.3 内置条件类型 <a
                    href="#t13010.6.3%20%E5%86%85%E7%BD%AE%E6%9D%A1%E4%BB%B6%E7%B1%BB%E5%9E%8B">
                    # </a></h4>
            <ul>
                <li>TS 在内置了一些常用的条件类型，可以在 <a
                        href="https://github.com/Microsoft/TypeScript/blob/c48662c891ce810f5627a0f6a8594049cccceeb5/lib/lib.es5.d.ts#L1291">lib.es5.d.ts</a>
                    中查看：</li>
                <li><a href="http://www.typescriptlang.org/docs/handbook/utility-types.html">utility-types</a></li>
            </ul>
            <h5 id="t13110.6.3.1 Exclude&lt;T, U&gt;">10.6.3.1 Exclude<t, u=""> <a
                        href="#t13110.6.3.1%20Exclude%3CT,%20U%3E">
                        # </a></t,>
            </h5>
            <ul>
                <li>从 T 可分配给的类型中排除 U</li>
            </ul>
            <pre><code class="lang-js">type Exclude&lt;T, U&gt; = T extends U ? never : T;

type  E = Exclude&lt;string|number,string&gt;;
<span class="hljs-keyword">let</span> e:E = <span class="hljs-number">10</span>;
</code></pre>
            <h5 id="t13210.6.3.2 Extract&lt;T, U&gt;">10.6.3.2 Extract<t, u=""> <a
                        href="#t13210.6.3.2%20Extract%3CT,%20U%3E">
                        # </a></t,>
            </h5>
            <ul>
                <li>从 T 可分配的类型中提取 U</li>
            </ul>
            <pre><code class="lang-js">type Extract&lt;T, U&gt; = T extends U ? T : never;

type  E = Extract&lt;string|number,string&gt;;
<span class="hljs-keyword">let</span> e:E = <span class="hljs-string">'1'</span>;
</code></pre>
            <h5 id="t13310.6.3.3 NonNullable">10.6.3.3 NonNullable <a href="#t13310.6.3.3%20NonNullable"> #
                </a></h5>
            <ul>
                <li>从 T 中排除 null 和 undefined</li>
            </ul>
            <pre><code class="lang-js">type NonNullable&lt;T&gt; = T extends <span class="hljs-literal">null</span> | <span class="hljs-literal">undefined</span> ? never : T;

type  E = NonNullable&lt;string|number|<span class="hljs-literal">null</span>|<span class="hljs-literal">undefined</span>&gt;;
<span class="hljs-keyword">let</span> e:E = <span class="hljs-literal">null</span>;
</code></pre>
            <h5 id="t13410.6.3.4 ReturnType">10.6.3.4 ReturnType <a href="#t13410.6.3.4%20ReturnType"> #
                </a></h5>
            <ul>
                <li><a
                        href="http://www.typescriptlang.org/docs/handbook/advanced-types.html#type-inference-in-conditional-types">infer</a>最早出现在此
                    <a href="https://github.com/Microsoft/TypeScript/pull/21496">PR</a> 中，表示在 <code>extends</code>
                    条件语句中待推断的类型变量</li>
                <li>获取函数类型的返回类型</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">export</span> {}
type ReturnType&lt;T extends (...args: any[]) =&gt; any&gt; = T extends (...args: any[]) =&gt; infer R ? R : any;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUserInfo</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> { <span class="hljs-attr">name</span>: <span class="hljs-string">"zhufeng"</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">10</span> };
}

<span class="hljs-comment">// 通过 ReturnType 将 getUserInfo 的返回值类型赋给了 UserInfo</span>
type UserInfo = ReturnType&lt;<span class="hljs-keyword">typeof</span> getUserInfo&gt;;

<span class="hljs-keyword">const</span> userA: UserInfo = {
    <span class="hljs-attr">name</span>: <span class="hljs-string">"zhufeng"</span>,
    <span class="hljs-attr">age</span>: <span class="hljs-number">10</span>
};
</code></pre>
            <h5 id="t13510.6.3.5 Parameters">10.6.3.5 Parameters <a href="#t13510.6.3.5%20Parameters"> #
                </a></h5>
            <ul>
                <li>Constructs a tuple type of the types of the parameters of a function type T</li>
                <li><a href="http://www.typescriptlang.org/docs/handbook/utility-types.html#parameterst">Parameters</a>
                </li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">export</span> {}
type Parameters&lt;T&gt; = T extends (...args: infer R) =&gt; any ? R : any;

type T0 = Parameters&lt;<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> string&gt;;  <span class="hljs-comment">// []</span>
type T1 = Parameters&lt;<span class="hljs-function">(<span class="hljs-params">s: string</span>) =&gt;</span> <span class="hljs-keyword">void</span>&gt;;  <span class="hljs-comment">// [string]</span>
type T2 = Parameters&lt;<span class="hljs-function">(<span class="hljs-params">&lt;T&gt;(arg: T</span>) =&gt;</span> T)&gt;;  <span class="hljs-comment">// [unknown]</span>
</code></pre>
            <h5 id="t13610.6.3.6 InstanceType">10.6.3.6 InstanceType <a href="#t13610.6.3.6%20InstanceType"> #
                </a></h5>
            <ul>
                <li>获取构造函数类型的实例类型</li>
                <li><a
                        href="http://www.typescriptlang.org/docs/handbook/utility-types.html#instancetypet">InstanceType</a>
                </li>
            </ul>
            <pre><code class="lang-js">type Constructor = <span class="hljs-keyword">new</span> (...args: any[]) =&gt; any;
type ConstructorParameters&lt;T extends Constructor&gt; = T extends <span class="hljs-keyword">new</span> (...args: infer P) =&gt; any ? P : never;
type InstanceType&lt;T extends Constructor&gt; = T extends <span class="hljs-keyword">new</span> (...args: any[]) =&gt; infer R ? R : any;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{
    <span class="hljs-attr">name</span>: string;
    <span class="hljs-keyword">constructor</span>(name: string) {
        <span class="hljs-keyword">this</span>.name = name;
    }
    getName() { <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">this</span>.name) }
}
<span class="hljs-comment">//构造函数参数</span>
type constructorParameters = ConstructorParameters&lt;<span class="hljs-keyword">typeof</span> Person&gt;;
<span class="hljs-keyword">let</span> params: constructorParameters = [<span class="hljs-string">'zhufeng'</span>]
<span class="hljs-comment">//实例类型</span>
type Instance = InstanceType&lt;<span class="hljs-keyword">typeof</span> Person&gt;;
<span class="hljs-keyword">let</span> instance: Instance = { <span class="hljs-attr">name</span>: <span class="hljs-string">'zhufeng'</span>, getName() { } };
</code></pre>
            <h5 id="t13710.6.3.7 infer+分布式">10.6.3.7 infer+分布式 <a
                    href="#t13710.6.3.7%20infer+%E5%88%86%E5%B8%83%E5%BC%8F">
                    # </a></h5>
            <ul>
                <li><a
                        href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types">distributive-conditional-types</a>
                </li>
                <li>「Distributive conditional types」主要用于拆分 extends 左边部分的联合类型</li>
                <li>「Distributive conditional types」是由「naked type parameter」构成的条件类型。而「naked type parameter」表示没有被 Wrapped
                    的类型（如：Array<t>、[T]、Promise<t> 等都是不是「naked type parameter」）。「Distributive conditional types」主要用于拆分
                            extends 左边部分的联合类型，举个例子：在条件类型 T extends U ? X : Y 中，当 T 是 A | B 时，会拆分成 A extends U ? X : Y |
                            B extends U ? X : Y；</t>
                    </t>
                </li>
                <li>
                    <p>利用在逆变位置上，同一类型变量的多个候选类型将会被推断为<a
                            href="https://github.com/Microsoft/TypeScript/pull/21496">交叉类型的特性</a></p>
                </li>
                <li>
                    <p>tuple转union</p>
                </li>
            </ul>
            <pre><code class="lang-js">type ElementOf&lt;T&gt; = T extends <span class="hljs-built_in">Array</span>&lt;infer E&gt; ? E : never;

type TTuple = [string, number];

type ToUnion = ElementOf&lt;TTuple&gt;; <span class="hljs-comment">// string | number</span>
</code></pre>
            <pre><code class="lang-js"><span class="hljs-comment">//联合类型（Union Types）表示取值可以为多种类型中的一种</span>
<span class="hljs-comment">//交叉类型（Intersection Types）表示将多个类型合并为一个类型</span>
<span class="hljs-comment">//联合类型转交叉类型</span>
<span class="hljs-comment">//union 转 intersection</span>
<span class="hljs-comment">//union 转 intersection 的操作多用于 mixin 中</span>
<span class="hljs-comment">//https://github.com/Microsoft/TypeScript/issues/27907</span>
type T1 = { <span class="hljs-attr">name</span>: string };
type T2 = { <span class="hljs-attr">age</span>: number };

type UnionToIntersection&lt;T&gt; = T extends { <span class="hljs-attr">a</span>: <span class="hljs-function">(<span class="hljs-params">x: infer U</span>) =&gt;</span> <span class="hljs-keyword">void</span>; b: <span class="hljs-function">(<span class="hljs-params">x: infer U</span>) =&gt;</span> <span class="hljs-keyword">void</span> } ? U : never;
type T3 = UnionToIntersection&lt;{ <span class="hljs-attr">a</span>: <span class="hljs-function">(<span class="hljs-params">x: T1</span>) =&gt;</span> <span class="hljs-keyword">void</span>; b: <span class="hljs-function">(<span class="hljs-params">x: T2</span>) =&gt;</span> <span class="hljs-keyword">void</span> }&gt;; <span class="hljs-comment">// T1 &amp; T2</span>
</code></pre>
            <h3 id="t13810.7 内置工具类型">10.7 内置工具类型 <a
                    href="#t13810.7%20%E5%86%85%E7%BD%AE%E5%B7%A5%E5%85%B7%E7%B1%BB%E5%9E%8B">
                    # </a></h3>
            <ul>
                <li>TS 中内置了一些工具类型来帮助我们更好地使用类型系统</li>
                <li><a
                        href="http://www.zhufengpeixun.com/strong/html/[utility-types](https://github.com/piotrwitek/utility-types">utility-types</a>)
                </li>
                <li>TypeScript中增加了对映射类型修饰符的控制</li>
                <li>具体而言，一个 <code>readonly</code> 或 <code>?</code> 修饰符在一个映射类型里可以用前缀 <code>+</code>
                    或<code>-</code>来表示这个修饰符应该被添加或移除</li>
            </ul>
            <table>
                <thead>
                    <tr>
                        <th style="text-align:left">符号</th>
                        <th style="text-align:left">含义</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td style="text-align:left">+?</td>
                        <td style="text-align:left">变为可选</td>
                    </tr>
                    <tr>
                        <td style="text-align:left">-?</td>
                        <td style="text-align:left">变为必选</td>
                    </tr>
                </tbody>
            </table>
            <h4 id="t13910.7.1 Partial">10.7.1 Partial <a href="#t13910.7.1%20Partial"> # </a>
            </h4>
            <ul>
                <li>Partial 可以将传入的属性由非可选变为可选，具体使用如下：</li>
            </ul>
            <pre><code class="lang-js">type Partial&lt;T&gt; = { [P <span class="hljs-keyword">in</span> keyof T]?: T[P] };

interface A {
  <span class="hljs-attr">a1</span>: string;
  a2: number;
  a3: boolean;
}

type aPartial = Partial&lt;A&gt;;

<span class="hljs-keyword">const</span> a: aPartial = {}; <span class="hljs-comment">// 不会报错</span>
</code></pre>
            <h4 id="t14010.7.2 类型递归">10.7.2 类型递归 <a href="#t14010.7.2%20%E7%B1%BB%E5%9E%8B%E9%80%92%E5%BD%92">
                    # </a></h4>
            <pre><code class="lang-js">interface Company {
    <span class="hljs-attr">id</span>: number
    <span class="hljs-attr">name</span>: string
}

interface Person {
    <span class="hljs-attr">id</span>: number
    <span class="hljs-attr">name</span>: string
    <span class="hljs-attr">company</span>: Company
}
type DeepPartial&lt;T&gt; = {
    [U <span class="hljs-keyword">in</span> keyof T]?: T[U] extends object
    ? DeepPartial&lt;T[U]&gt;
    : T[U]
};

type R2 = DeepPartial&lt;Person&gt;
</code></pre>
            <h4 id="t14110.7.3 Required">10.7.3 Required <a href="#t14110.7.3%20Required"> # </a>
            </h4>
            <ul>
                <li>Required 可以将传入的属性中的可选项变为必选项，这里用了 -? 修饰符来实现。</li>
            </ul>
            <pre><code class="lang-js">interface Person{
  <span class="hljs-attr">name</span>:string;
  age:number;
  gender?:<span class="hljs-string">'male'</span>|<span class="hljs-string">'female'</span>;
}
<span class="hljs-comment">/**
 * type Require&lt;T&gt; = { [P in keyof T]-?: T[P] };
 */</span>
<span class="hljs-keyword">let</span> p:Required&lt;Person&gt; = {
  <span class="hljs-attr">name</span>:<span class="hljs-string">'zhufeng'</span>,
  <span class="hljs-attr">age</span>:<span class="hljs-number">10</span>,
  <span class="hljs-comment">//gender:'male'</span>
}
</code></pre>
            <h4 id="t14210.7.4 Readonly">10.7.4 Readonly <a href="#t14210.7.4%20Readonly"> # </a>
            </h4>
            <ul>
                <li>Readonly 通过为传入的属性每一项都加上 readonly 修饰符来实现。</li>
            </ul>
            <pre><code class="lang-js">interface Person{
  <span class="hljs-attr">name</span>:string;
  age:number;
  gender?:<span class="hljs-string">'male'</span>|<span class="hljs-string">'female'</span>;
}
<span class="hljs-comment">//type Readonly&lt;T&gt; = { readonly [P in keyof T]: T[P] };</span>
<span class="hljs-keyword">let</span> p:Readonly&lt;Person&gt; = {
  <span class="hljs-attr">name</span>:<span class="hljs-string">'zhufeng'</span>,
  <span class="hljs-attr">age</span>:<span class="hljs-number">10</span>,
  <span class="hljs-attr">gender</span>:<span class="hljs-string">'male'</span>
}
p.age = <span class="hljs-number">11</span>;
</code></pre>
            <h4 id="t14310.7.5 Pick">10.7.5 Pick <a href="#t14310.7.5%20Pick"> # </a></h4>
            <ul>
                <li>Pick 能够帮助我们从传入的属性中摘取某一项返回</li>
            </ul>
            <pre><code class="lang-js">interface Animal {
  <span class="hljs-attr">name</span>: string;
  age: number;
  gender:number
}
<span class="hljs-comment">/**
 * From T pick a set of properties K
 * type Pick&lt;T, K extends keyof T&gt; = { [P in K]: T[P] };
 */</span>
<span class="hljs-comment">// 摘取 Animal 中的 name 属性</span>
interface Person {
    <span class="hljs-attr">name</span>: string;
    age: number;
    married: boolean
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">pick</span>&lt;<span class="hljs-title">T</span>, <span class="hljs-title">K</span> <span class="hljs-title">extends</span> <span class="hljs-title">keyof</span> <span class="hljs-title">T</span>&gt;(<span class="hljs-params">obj: T, keys: K[]</span>): <span class="hljs-title">Pick</span>&lt;<span class="hljs-title">T</span>, <span class="hljs-title">K</span>&gt; </span>{
    <span class="hljs-keyword">const</span> result: any = {};
    keys.map(<span class="hljs-function"><span class="hljs-params">key</span> =&gt;</span> {
        result[key] = obj[key];
    });
    <span class="hljs-keyword">return</span> result
}
<span class="hljs-keyword">let</span> person: Person = { <span class="hljs-attr">name</span>: <span class="hljs-string">'zhufeng'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">10</span>, <span class="hljs-attr">married</span>: <span class="hljs-literal">true</span> };
<span class="hljs-keyword">let</span> result: Pick&lt;Person, <span class="hljs-string">'name'</span> | <span class="hljs-string">'age'</span>&gt; = pick&lt;Person, <span class="hljs-string">'name'</span> | <span class="hljs-string">'age'</span>&gt;(person, [<span class="hljs-string">'name'</span>, <span class="hljs-string">'age'</span>]);
<span class="hljs-built_in">console</span>.log(result);
</code></pre>
            <h4 id="t14410.7.6 Record">10.7.6 Record <a href="#t14410.7.6%20Record"> # </a>
            </h4>
            <ul>
                <li>Record 是 TypeScript 的一个高级类型</li>
                <li>他会将一个类型的所有属性值都映射到另一个类型上并创造一个新的类型</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-comment">/**
 * Construct a type with a set of properties K of type T
 */</span>
type Record&lt;K extends keyof any, T&gt; = {
    [P <span class="hljs-keyword">in</span> K]: T;
};
</code></pre>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mapObject</span>&lt;<span class="hljs-title">K</span> <span class="hljs-title">extends</span> <span class="hljs-title">string</span> | <span class="hljs-title">number</span>, <span class="hljs-title">T</span>, <span class="hljs-title">U</span>&gt;(<span class="hljs-params">obj: Record&lt;K, T&gt;, map: (x: T</span>) =&gt; <span class="hljs-title">U</span>): <span class="hljs-title">Record</span>&lt;<span class="hljs-title">K</span>, <span class="hljs-title">U</span>&gt; </span>{
    <span class="hljs-keyword">let</span> result: any = {};
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> key <span class="hljs-keyword">in</span> obj) {
        result[key] = map(obj[key]);
    }
    <span class="hljs-keyword">return</span> result;
}
<span class="hljs-keyword">let</span> names = { <span class="hljs-number">0</span>: <span class="hljs-string">'hello'</span>, <span class="hljs-number">1</span>: <span class="hljs-string">'world'</span> };
<span class="hljs-keyword">let</span> lengths = mapObject&lt;string | number, string, number&gt;<span class="hljs-function">(<span class="hljs-params">names, (s: string</span>) =&gt;</span> s.length);
<span class="hljs-built_in">console</span>.log(lengths);<span class="hljs-comment">//{ '0': 5, '1': 5 }</span>
</code></pre>
            <pre><code class="lang-js">type Point = <span class="hljs-string">'x'</span> | <span class="hljs-string">'y'</span>;
type PointList = Record&lt;Point, { <span class="hljs-attr">value</span>: number }&gt;
<span class="hljs-keyword">const</span> cars: PointList = {
    <span class="hljs-attr">x</span>: { <span class="hljs-attr">value</span>: <span class="hljs-number">10</span> },
    <span class="hljs-attr">y</span>: { <span class="hljs-attr">value</span>: <span class="hljs-number">20</span> },
}
</code></pre>
            <h3 id="t14510.8 自定义高级类型">10.8 自定义高级类型 <a
                    href="#t14510.8%20%E8%87%AA%E5%AE%9A%E4%B9%89%E9%AB%98%E7%BA%A7%E7%B1%BB%E5%9E%8B">
                    # </a></h3>
            <ul>
                <li><a href="https://github.com/piotrwitek/utility-types">utility-types</a></li>
            </ul>
            <h4 id="t14610.8.1 Proxy">10.8.1 Proxy <a href="#t14610.8.1%20Proxy"> # </a></h4>
            <pre><code class="lang-js">type <span class="hljs-built_in">Proxy</span>&lt;T&gt; = {
    <span class="hljs-keyword">get</span>(): T;
    <span class="hljs-keyword">set</span>(value: T): void;
}
type Proxify&lt;T&gt; = {
    [P <span class="hljs-keyword">in</span> keyof T]: <span class="hljs-built_in">Proxy</span>&lt;T[P]&gt;
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">proxify</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">obj: T</span>): <span class="hljs-title">Proxify</span>&lt;<span class="hljs-title">T</span>&gt; </span>{
    <span class="hljs-keyword">let</span> result = {} <span class="hljs-keyword">as</span> Proxify&lt;T&gt;;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> key <span class="hljs-keyword">in</span> obj) {
        result[key] = {
            <span class="hljs-attr">get</span>: <span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> obj[key],
            <span class="hljs-attr">set</span>: <span class="hljs-function">(<span class="hljs-params">value</span>) =&gt;</span> obj[key] = value
        }
    }
    <span class="hljs-keyword">return</span> result;
}
<span class="hljs-keyword">let</span> props = {
    <span class="hljs-attr">name</span>: <span class="hljs-string">'zhufeng'</span>,
    <span class="hljs-attr">age</span>: <span class="hljs-number">10</span>
}
<span class="hljs-keyword">let</span> proxyProps = proxify(props);
<span class="hljs-built_in">console</span>.log(proxyProps);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">unProxify</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">t: Proxify&lt;T&gt;</span>): <span class="hljs-title">T</span> </span>{
    <span class="hljs-keyword">let</span> result = {} <span class="hljs-keyword">as</span> T;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> k <span class="hljs-keyword">in</span> t) {
        result[k] = t[k].get();
    }
    <span class="hljs-keyword">return</span> result;
}

<span class="hljs-keyword">let</span> originProps = unProxify(proxyProps);
<span class="hljs-built_in">console</span>.log(originProps);
</code></pre>
            <h4 id="t14710.8.2 SetDifference">10.8.2 SetDifference <a href="#t14710.8.2%20SetDifference"> #
                </a></h4>
            <ul>
                <li>SetDifference (same as Exclude)</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-comment">/**
 * SetDifference (same as Exclude)
 * <span class="hljs-doctag">@desc </span>Set difference of given union types `A` and `B`
 * <span class="hljs-doctag">@example</span>
 *   // Expect: "1"
 *   SetDifference&lt;'1' | '2' | '3', '2' | '3' | '4'&gt;;
 *
 *   // Expect: string | number
 *   SetDifference&lt;string | number | (() =&gt; void), Function&gt;;
 */</span>
<span class="hljs-keyword">export</span> type SetDifference&lt;A, B&gt; = A extends B ? never : A;
</code></pre>
            <h4 id="t14810.8.3 Omit">10.8.3 Omit <a href="#t14810.8.3%20Omit"> # </a></h4>
            <ul>
                <li>Exclude 的作用是从 T 中排除出可分配给 U的元素.</li>
                <li>Omit&lt;T, K&gt;的作用是忽略T中的某些属性</li>
                <li>Omit = Exclude + Pick</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-comment">/**
 * Omit (complements Pick)
 * <span class="hljs-doctag">@desc </span>From `T` remove a set of properties by key `K`
 * <span class="hljs-doctag">@example</span>
 *   type Props = { name: string; age: number; visible: boolean };
 *
 *   // Expect: { name: string; visible: boolean; }
 *   type Props = Omit&lt;Props, 'age'&gt;;
 */</span>
<span class="hljs-keyword">export</span> type Omit&lt;T, K extends keyof any&gt; = Pick&lt;T, SetDifference&lt;keyof T, K&gt;&gt;;
</code></pre>
            <h4 id="t14910.8.4 Diff">10.8.4 Diff <a href="#t14910.8.4%20Diff"> # </a></h4>
            <pre><code class="lang-js"><span class="hljs-comment">/**
 * Diff
 * <span class="hljs-doctag">@desc </span>From `T` remove properties that exist in `U`
 * <span class="hljs-doctag">@example</span>
 *   type Props = { name: string; age: number; visible: boolean };
 *   type DefaultProps = { age: number };
 *
 *   // Expect: { name: string; visible: boolean; }
 *   type DiffProps = Diff&lt;Props, DefaultProps&gt;;
 */</span>
<span class="hljs-keyword">export</span> type Diff&lt;T extends object, U extends object&gt; = Pick&lt;
  T,
  SetDifference&lt;keyof T, keyof U&gt;
&gt;;
</code></pre>
            <h4 id="t15010.8.5 Intersection">10.8.5 Intersection <a href="#t15010.8.5%20Intersection"> #
                </a></h4>
            <pre><code class="lang-js"><span class="hljs-comment">/**
 * Intersection
 * <span class="hljs-doctag">@desc </span>From `T` pick properties that exist in `U`
 * <span class="hljs-doctag">@example</span>
 *   type Props = { name: string; age: number; visible: boolean };
 *   type DefaultProps = { age: number };
 *
 *   // Expect: { age: number; }
 *   type DuplicateProps = Intersection&lt;Props, DefaultProps&gt;;
 */</span>
<span class="hljs-keyword">export</span> type Intersection&lt;T extends object, U extends object&gt; = Pick&lt;
  T,
  Extract&lt;keyof T, keyof U&gt; &amp; Extract&lt;keyof U, keyof T&gt;
&gt;;
</code></pre>
            <h4 id="t15110.8.6 Overwrite">10.8.6 Overwrite <a href="#t15110.8.6%20Overwrite"> # </a>
            </h4>
            <ul>
                <li>Overwrite&lt;T, U&gt;顾名思义,是用U的属性覆盖T的相同属性.</li>
                <li><a
                        href="https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts">mapped-types</a>
                </li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-comment">/**
 * Overwrite
 * <span class="hljs-doctag">@desc </span>From `U` overwrite properties to `T`
 * <span class="hljs-doctag">@example</span>
 *   type Props = { name: string; age: number; visible: boolean };
 *   type NewProps = { age: string; other: string };
 *
 *   // Expect: { name: string; age: string; visible: boolean; }
 *   type ReplacedProps = Overwrite&lt;Props, NewProps&gt;;
 */</span>
<span class="hljs-keyword">export</span> type Overwrite&lt;
  T extends object,
  U extends object,
  I = Diff&lt;T, U&gt; &amp; Intersection&lt;U, T&gt;
&gt; = Pick&lt;I, keyof I&gt;;

type Props = { <span class="hljs-attr">name</span>: string; age: number; visible: boolean };
type NewProps = { <span class="hljs-attr">age</span>: string; other: string };

<span class="hljs-comment">// Expect: { name: string; age: string; visible: boolean; }</span>
type ReplacedProps = Overwrite&lt;Props, NewProps&gt;;

</code></pre>
            <h4 id="t15210.8.7 Merge">10.8.7 Merge <a href="#t15210.8.7%20Merge"> # </a></h4>
            <ul>
                <li>Merge&lt;O1, O2&gt;的作用是将两个对象的属性合并:</li>
                <li>Merge&lt;O1, O2&gt; = Compute<a> + Omit&lt;U, T&gt;</a></li>
            </ul>
            <pre><code class="lang-js">type O1 = {
  <span class="hljs-attr">id</span>: number;
  name: string;
};

type O2 = {
  <span class="hljs-attr">id</span>: number;
  age: number;
};


<span class="hljs-comment">//Compute的作用是将交叉类型合并</span>
type Compute&lt;A extends any&gt; = A extends <span class="hljs-built_in">Function</span> ? A : { [K <span class="hljs-keyword">in</span> keyof A]: A[K] };

type R1 = Compute&lt;{ <span class="hljs-attr">x</span>: <span class="hljs-string">"x"</span> } &amp; { <span class="hljs-attr">y</span>: <span class="hljs-string">"y"</span> }&gt;;
type Merge&lt;O1 extends object, O2 extends object&gt; = Compute&lt;
  O1 &amp; Omit&lt;O2, keyof O1&gt;
&gt;;

type R2 = Merge&lt;O1, O2&gt;;
</code></pre>
            <h4 id="t15310.8.8 Mutable">10.8.8 Mutable <a href="#t15310.8.8%20Mutable"> # </a>
            </h4>
            <ul>
                <li>将 T 的所有属性的 <code>readonly</code> 移除</li>
            </ul>
            <pre><code class="lang-js">type Mutable&lt;T&gt; = {
  -readonly [P <span class="hljs-keyword">in</span> keyof T]: T[P]
}
</code></pre>
            <h3 id="t15410.9 面试题综合实战">10.9 面试题综合实战 <a
                    href="#t15410.9%20%E9%9D%A2%E8%AF%95%E9%A2%98%E7%BB%BC%E5%90%88%E5%AE%9E%E6%88%98">
                    # </a></h3>
            <ul>
                <li><code>infer</code> 关键字就是声明一个类型变量,当类型系统给足条件的时候类型就会被推断出来</li>
                <li><a href="https://github.com/LeetCode-OpenSource/hire/blob/master/typescript_zh.md">typescript_zh</a>
                </li>
                <li><a href="https://codesandbox.io/s/4tmtp">codesandbox</a></li>
            </ul>
            <pre><code class="lang-js">interface Action&lt;T&gt; {
    payload?: T;
    type: string;
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EffectModule</span> </span>{
    count = <span class="hljs-number">1</span>;
    message = <span class="hljs-string">"hello!"</span>;

    delay(input: <span class="hljs-built_in">Promise</span>&lt;number&gt;): <span class="hljs-built_in">Promise</span>&lt;Action&lt;string&gt;&gt; {
        <span class="hljs-keyword">let</span> action: <span class="hljs-built_in">Promise</span>&lt;Action&lt;string&gt;&gt; =  input.then(<span class="hljs-function"><span class="hljs-params">i</span> =&gt;</span> ({
            <span class="hljs-attr">payload</span>: <span class="hljs-string">`hello <span class="hljs-subst">${i}</span>!`</span>,
            <span class="hljs-attr">type</span>: <span class="hljs-string">'delay'</span>
        }));
        <span class="hljs-keyword">return</span> action;
    }

    setMessage(action: Action&lt;<span class="hljs-built_in">Date</span>&gt;): Action&lt;number&gt; {
        <span class="hljs-keyword">let</span> action2: Action&lt;number&gt; = {
            <span class="hljs-attr">payload</span>: action.payload!.getMilliseconds(),
            <span class="hljs-attr">type</span>: <span class="hljs-string">"set-message"</span>
        };
        <span class="hljs-keyword">return</span> action2;
    }
}
<span class="hljs-comment">//把 EffectModule 中的方法名取出来</span>
type methodsPick&lt;T&gt; = { [K <span class="hljs-keyword">in</span> keyof T]: T[K] extends <span class="hljs-built_in">Function</span> ? K : never }[keyof T];
<span class="hljs-comment">//定义转换前后的方法</span>
type asyncMethod&lt;T, U&gt; = <span class="hljs-function">(<span class="hljs-params">input: <span class="hljs-built_in">Promise</span>&lt;T&gt;</span>) =&gt;</span> <span class="hljs-built_in">Promise</span>&lt;Action&lt;U&gt;&gt; <span class="hljs-comment">// 转换前</span>
type asyncMethodConnect&lt;T, U&gt; = <span class="hljs-function">(<span class="hljs-params">input: T</span>) =&gt;</span> Action&lt;U&gt; <span class="hljs-comment">// 转换后</span>
type syncMethod&lt;T, U&gt; = <span class="hljs-function">(<span class="hljs-params">action: Action&lt;T&gt;</span>) =&gt;</span> Action&lt;U&gt; <span class="hljs-comment">// 转换前</span>
type syncMethodConnect&lt;T, U&gt; = <span class="hljs-function">(<span class="hljs-params">action: T</span>) =&gt;</span> Action&lt;U&gt; <span class="hljs-comment">// 转换后</span>
<span class="hljs-comment">//条件类型+推断类型</span>
type EffectModuleMethodsConnect&lt;T&gt; = T extends asyncMethod&lt;infer U, infer V&gt;
    ? asyncMethodConnect&lt;U, V&gt;
    : T extends syncMethod&lt;infer U, infer V&gt;
    ? syncMethodConnect&lt;U, V&gt;
    : never
type EffectModuleMethods = methodsPick&lt;EffectModule&gt;
<span class="hljs-comment">//映射类型</span>
type Connect = <span class="hljs-function">(<span class="hljs-params"><span class="hljs-built_in">module</span>: EffectModule</span>) =&gt;</span> {
    [M <span class="hljs-keyword">in</span> EffectModuleMethods]: EffectModuleMethodsConnect&lt;EffectModule[M]&gt;
} 
type Connected = {
    delay(input: number): Action&lt;string&gt;;
    setMessage(action: <span class="hljs-built_in">Date</span>): Action&lt;number&gt;;
};
<span class="hljs-keyword">const</span> connect: Connect = (m: EffectModule): <span class="hljs-function"><span class="hljs-params">Connected</span> =&gt;</span> ({
    <span class="hljs-attr">delay</span>: <span class="hljs-function">(<span class="hljs-params">input: number</span>) =&gt;</span> ({
        <span class="hljs-attr">type</span>: <span class="hljs-string">'delay'</span>,
        <span class="hljs-attr">payload</span>: <span class="hljs-string">`hello 2`</span>
    }),
    <span class="hljs-attr">setMessage</span>: <span class="hljs-function">(<span class="hljs-params">input: <span class="hljs-built_in">Date</span></span>) =&gt;</span> ({
        <span class="hljs-attr">type</span>: <span class="hljs-string">"set-message"</span>,
        <span class="hljs-attr">payload</span>: input.getMilliseconds()
    })
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> connected: Connected = connect(<span class="hljs-keyword">new</span> EffectModule());


</code></pre>
            <h2 id="t15511. 模块VS命名空间">11. 模块VS命名空间 <a
                    href="#t15511.%20%E6%A8%A1%E5%9D%97VS%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4">
                    # </a></h2>
            <ul>
                <li><a href="https://blog.higan.me/namespace-and-module-in-typescript/">namespace-and-module</a>
                    <h4 id="t15611.1 模块">11.1 模块 <a href="#t15611.1%20%E6%A8%A1%E5%9D%97">
                            # </a></h4>
                    <h5 id="t15711.1.1 全局模块">11.1.1 全局模块 <a href="#t15711.1.1%20%E5%85%A8%E5%B1%80%E6%A8%A1%E5%9D%97">
                            # </a></h5>
                </li>
                <li>在默认情况下，当你开始在一个新的 TypeScript 文件中写下代码时，它处于全局命名空间中</li>
                <li>使用全局变量空间是危险的，因为它会与文件内的代码命名冲突。我们推荐使用下文中将要提到的文件模块</li>
            </ul>
            <p>foo.ts</p>
            <pre><code class="lang-js"><span class="hljs-keyword">const</span> foo = <span class="hljs-number">123</span>;
</code></pre>
            <p>bar.ts</p>
            <pre><code class="lang-js"><span class="hljs-keyword">const</span> bar = foo; <span class="hljs-comment">// allowed</span>
</code></pre>
            <h5 id="t15811.1.2 文件模块">11.1.2 文件模块 <a href="#t15811.1.2%20%E6%96%87%E4%BB%B6%E6%A8%A1%E5%9D%97">
                    # </a></h5>
            <ul>
                <li>文件模块也被称为外部模块。如果在你的 TypeScript 文件的根级别位置含有 import 或者 export，那么它会在这个文件中创建一个本地的作用域</li>
                <li>模块是TS中外部模块的简称，侧重于代码和复用</li>
                <li>模块在期自身的作用域里执行，而不是在全局作用域里</li>
                <li>一个模块里的变量、函数、类等在外部是不可见的，除非你把它导出</li>
                <li>如果想要使用一个模块里导出的变量，则需要导入</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> a = <span class="hljs-number">1</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> b = <span class="hljs-number">2</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-string">'zhufeng'</span>;
</code></pre>
            <pre><code class="lang-js"><span class="hljs-keyword">import</span> name, { a, b } <span class="hljs-keyword">from</span> <span class="hljs-string">'./1'</span>;
<span class="hljs-built_in">console</span>.log(name, a, b);
</code></pre>
            <h5 id="t15911.1.3 模块规范">11.1.3 模块规范 <a href="#t15911.1.3%20%E6%A8%A1%E5%9D%97%E8%A7%84%E8%8C%83">
                    # </a></h5>
            <ul>
                <li>AMD：不要使用它，它仅能在浏览器工作；</li>
                <li>SystemJS：这是一个好的实验，已经被 ES 模块替代；</li>
                <li>ES 模块：它并没有准备好。</li>
                <li>使用 module: commonjs 选项来替代这些模式，将会是一个好的主意</li>
            </ul>
            <h4 id="t16011.2 命名空间">11.2 命名空间 <a href="#t16011.2%20%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4">
                    # </a></h4>
            <ul>
                <li>在代码量较大的情况下，为了避免命名空间冲突，可以将相似的函数、类、接口放置到命名空间内</li>
                <li>命名空间可以将代码包裹起来，只对外暴露需要在外部访问的对象，命名空间内通过<code>export</code>向外导出</li>
                <li>命名空间是内部模块，主要用于组织代码，避免命名冲突</li>
            </ul>
            <h5 id="t16111.2.1 内部划分">11.2.1 内部划分 <a href="#t16111.2.1%20%E5%86%85%E9%83%A8%E5%88%92%E5%88%86">
                    # </a></h5>
            <pre><code class="lang-js"><span class="hljs-keyword">export</span> namespace zoo {
    <span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> </span>{ eat() { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'zoo dog'</span>); } }
}
<span class="hljs-keyword">export</span> namespace home {
    <span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> </span>{ eat() { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'home dog'</span>); } }
}
<span class="hljs-keyword">let</span> dog_of_zoo = <span class="hljs-keyword">new</span> zoo.Dog();
dog_of_zoo.eat();
<span class="hljs-keyword">let</span> dog_of_home = <span class="hljs-keyword">new</span> home.Dog();
dog_of_home.eat();
</code></pre>
            <pre><code class="lang-js"><span class="hljs-keyword">import</span> { zoo } <span class="hljs-keyword">from</span> <span class="hljs-string">'./3'</span>;
<span class="hljs-keyword">let</span> dog_of_zoo = <span class="hljs-keyword">new</span> zoo.Dog();
dog_of_zoo.eat();
</code></pre>
            <h5 id="t16211.2.2 原理">11.2.2 原理 <a href="#t16211.2.2%20%E5%8E%9F%E7%90%86">
                    # </a></h5>
            <ul>
                <li>其实一个命名空间本质上一个对象，它的作用是将一系列相关的全局变量组织到一个对象的属性</li>
            </ul>
            <pre><code class="lang-js">namespace Numbers {
    <span class="hljs-keyword">export</span> <span class="hljs-keyword">let</span> a = <span class="hljs-number">1</span>;
    <span class="hljs-keyword">export</span> <span class="hljs-keyword">let</span> b = <span class="hljs-number">2</span>;
    <span class="hljs-keyword">export</span> <span class="hljs-keyword">let</span> c = <span class="hljs-number">3</span>;
}
</code></pre>
            <pre><code class="lang-js"><span class="hljs-keyword">var</span> Numbers;
(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Numbers</span>) </span>{
    Numbers.a = <span class="hljs-number">1</span>;
    Numbers.b = <span class="hljs-number">2</span>;
    Numbers.c = <span class="hljs-number">3</span>;
})(Numbers || (Numbers = {}));
</code></pre>
            <h4 id="t16311.3 文件，模块与命名空间">11.3 文件，模块与命名空间 <a
                    href="#t16311.3%20%E6%96%87%E4%BB%B6%EF%BC%8C%E6%A8%A1%E5%9D%97%E4%B8%8E%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4">
                    # </a></h4>
            <h5 id="t16411.3.1 文件和模块">11.3.1 文件和模块 <a
                    href="#t16411.3.1%20%E6%96%87%E4%BB%B6%E5%92%8C%E6%A8%A1%E5%9D%97">
                    # </a></h5>
            <ul>
                <li>每个 module都不一样
                    src\table1.ts
                    <pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-built_in">module</span> Box{
  <span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book1</span></span>{}
}
</code></pre>
                </li>
            </ul>
            <p>src\table2.ts</p>
            <pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-built_in">module</span> Box{
    <span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book1</span></span>{}
}
</code></pre>
            <p>src\table3.ts</p>
            <pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-built_in">module</span> Box{
    <span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book1</span></span>{}
}
</code></pre>
            <h5 id="t16511.3.2 空间">11.3.2 空间 <a href="#t16511.3.2%20%E7%A9%BA%E9%97%B4">
                    # </a></h5>
            <ul>
                <li>namespace 和 module 不一样，namespace 在全局空间中具有唯一性</li>
            </ul>
            <p>src\table1.ts</p>
            <pre><code class="lang-js">namespace  Box{
    <span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book1</span></span>{}
}
</code></pre>
            <p>src\table2.ts</p>
            <pre><code class="lang-js">namespace  Box{
    <span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book1</span></span>{}
}
</code></pre>
            <p>src\table3.ts</p>
            <pre><code class="lang-js">namespace  Box{
    <span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book1</span></span>{}
}
</code></pre>
            <h5 id="t16611.3.3 文件">11.3.3 文件 <a href="#t16611.3.3%20%E6%96%87%E4%BB%B6">
                    # </a></h5>
            <ul>
                <li>每个文件是独立的</li>
            </ul>
            <p>src\table1.ts</p>
            <pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book1</span> </span>{ }
</code></pre>
            <p>src\table2.ts</p>
            <pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book1</span> </span>{ }
</code></pre>
            <p>src\table3.ts</p>
            <pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book1</span> </span>{ }
</code></pre>
            <h2 id="t16712.类型声明">12.类型声明 <a href="#t16712.%E7%B1%BB%E5%9E%8B%E5%A3%B0%E6%98%8E">
                    # </a></h2>
            <ul>
                <li>声明文件可以让我们不需要将JS重构为TS，只需要加上声明文件就可以使用系统</li>
                <li>类型声明在编译的时候都会被删除，不会影响真正的代码</li>
                <li>关键字 declare 表示声明的意思,我们可以用它来做出各种声明:</li>
            </ul>
            <pre><code class="lang-js">declare <span class="hljs-keyword">var</span> 声明全局变量
declare <span class="hljs-function"><span class="hljs-keyword">function</span> 声明全局方法
<span class="hljs-title">declare</span> <span class="hljs-title">class</span> 声明全局类
<span class="hljs-title">declare</span> <span class="hljs-title">enum</span> 声明全局枚举类型
<span class="hljs-title">declare</span> <span class="hljs-title">namespace</span> 声明(<span class="hljs-params">含有子属性的</span>)全局对象
<span class="hljs-title">interface</span> 和 <span class="hljs-title">type</span> 声明全局类型
</span></code></pre>
            <h3 id="t16812.1 普通类型声明">12.1 普通类型声明 <a
                    href="#t16812.1%20%E6%99%AE%E9%80%9A%E7%B1%BB%E5%9E%8B%E5%A3%B0%E6%98%8E">
                    # </a></h3>
            <pre><code class="lang-js">declare <span class="hljs-keyword">let</span> name: string;  <span class="hljs-comment">//变量</span>
declare <span class="hljs-keyword">let</span> age: number;  <span class="hljs-comment">//变量</span>
declare <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getName</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>;  //方法
<span class="hljs-title">declare</span> <span class="hljs-title">class</span> <span class="hljs-title">Animal</span> </span>{ name: string }  <span class="hljs-comment">//类</span>
<span class="hljs-built_in">console</span>.log(name, age);
getName();
<span class="hljs-keyword">new</span> Animal();
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {};
</code></pre>
            <p>声明jQuery对象</p>
            <pre><code class="lang-js">declare <span class="hljs-keyword">const</span> $: <span class="hljs-function">(<span class="hljs-params">selector: string</span>) =&gt;</span> { <span class="hljs-comment">//变量</span>
    click(): <span class="hljs-keyword">void</span>;
    width(length: number): <span class="hljs-keyword">void</span>;
};
$(<span class="hljs-string">'#root'</span>).click();
<span class="hljs-built_in">console</span>.log($(<span class="hljs-string">'#root'</span>).width);
</code></pre>
            <h3 id="t16912.2 外部枚举">12.2 外部枚举 <a href="#t16912.2%20%E5%A4%96%E9%83%A8%E6%9E%9A%E4%B8%BE">
                    # </a></h3>
            <ul>
                <li>外部枚举是使用<code>declare enum</code>定义的枚举类型</li>
                <li>外部枚举用来描述已经存在的枚举类型的形状</li>
            </ul>
            <pre><code class="lang-js">declare enum Seasons {
    Spring,
    Summer,
    Autumn,
    Winter
}

<span class="hljs-keyword">let</span> seasons = [
    Seasons.Spring,
    Seasons.Summer,
    Seasons.Autumn,
    Seasons.Winter
];
</code></pre>
            <p><code>declare</code> 定义的类型只会用于编译时的检查，编译结果中会被删除。上例的编译结果如下</p>
            <pre><code class="lang-js"><span class="hljs-keyword">var</span> seasons = [
    Seasons.Spring,
    Seasons.Summer,
    Seasons.Autumn,
    Seasons.Winter
];
</code></pre>
            <p>也可以同时使用<code>declare</code> 和 <code>const</code></p>
            <pre><code class="lang-js">declare <span class="hljs-keyword">const</span> enum Seasons {
    Spring,
    Summer,
    Autumn,
    Winter
}

<span class="hljs-keyword">let</span> seasons = [
    Seasons.Spring,
    Seasons.Summer,
    Seasons.Autumn,
    Seasons.Winter
];
</code></pre>
            <p>编译结果</p>
            <pre><code class="lang-js"><span class="hljs-keyword">var</span> seasons = [
    <span class="hljs-number">0</span> <span class="hljs-comment">/* Spring */</span>,
    <span class="hljs-number">1</span> <span class="hljs-comment">/* Summer */</span>,
    <span class="hljs-number">2</span> <span class="hljs-comment">/* Autumn */</span>,
    <span class="hljs-number">3</span> <span class="hljs-comment">/* Winter */</span>
];
</code></pre>
            <h3 id="t17012.3 namespace">12.3 namespace <a href="#t17012.3%20namespace"> # </a>
            </h3>
            <ul>
                <li>如果一个全局变量包括了很多子属性，可能使用namespace</li>
                <li>在声明文件中的<code>namespace</code>表示一个全局变量包含很多子属性</li>
                <li>在命名空间内部不需要使用 declare 声明属性或方法</li>
            </ul>
            <pre><code class="lang-js">declare namespace ${
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ajax</span>(<span class="hljs-params">url:string,settings:any</span>):<span class="hljs-title">void</span>;
    <span class="hljs-title">let</span> <span class="hljs-title">name</span>:<span class="hljs-title">string</span>;
    <span class="hljs-title">namespace</span> <span class="hljs-title">fn</span> </span>{
        <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">extend</span>(<span class="hljs-params">object:any</span>):<span class="hljs-title">void</span>;
    }
}
<span class="hljs-title">$</span>.<span class="hljs-title">ajax</span>(<span class="hljs-params"><span class="hljs-string">'/api/users'</span>,{}</span>);
<span class="hljs-title">$</span>.<span class="hljs-title">fn</span>.<span class="hljs-title">extend</span>(<span class="hljs-params">{
    log:function(message:any</span>)</span>{
        <span class="hljs-built_in">console</span>.log(message);
    }
});
<span class="hljs-keyword">export</span> {};
</code></pre>
            <h3 id="t17112.4 类型声明文件">12.4 类型声明文件 <a
                    href="#t17112.4%20%E7%B1%BB%E5%9E%8B%E5%A3%B0%E6%98%8E%E6%96%87%E4%BB%B6">
                    # </a></h3>
            <ul>
                <li>我们可以把类型声明放在一个单独的类型声明文件中</li>
                <li>可以在类型声明文件中使用类型声明</li>
                <li>文件命名规范为<code>*.d.ts</code></li>
                <li>观看类型声明文件有助于了解库的使用方式</li>
            </ul>
            <h4 id="t17212.4.1 jquery.d.ts">12.4.1 jquery.d.ts <a href="#t17212.4.1%20jquery.d.ts"> #
                </a></h4>
            <p>typings\jquery.d.ts</p>
            <pre><code class="lang-ts"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> $:<span class="hljs-function">(<span class="hljs-params">selector:<span class="hljs-built_in">string</span></span>)=&gt;</span>{
    click():<span class="hljs-built_in">void</span>;
    width(length:<span class="hljs-built_in">number</span>):<span class="hljs-built_in">void</span>;
}
</code></pre>
            <h4 id="t17312.4.2 tsconfig.json">12.4.2 tsconfig.json <a href="#t17312.4.2%20tsconfig.json"> #
                </a></h4>
            <p>tsconfig.json</p>
            <pre><code class="lang-json">{
  <span class="hljs-attr">"compilerOptions"</span>: {
    <span class="hljs-attr">"module"</span>: <span class="hljs-string">"commonjs"</span>,
    <span class="hljs-attr">"target"</span>: <span class="hljs-string">"ES2015"</span>,  
    <span class="hljs-attr">"outDir"</span>:<span class="hljs-string">"lib"</span>
  },
  <span class="hljs-attr">"include"</span>: [
    <span class="hljs-string">"src/**/*"</span>,
    <span class="hljs-string">"typings/**/*"</span>
  ]
}
</code></pre>
            <h4 id="t17412.4.3 test.js">12.4.3 test.js <a href="#t17412.4.3%20test.js"> # </a>
            </h4>
            <p>src\test.ts</p>
            <pre><code class="lang-js">$(<span class="hljs-string">'#button'</span>).click();
$(<span class="hljs-string">'#button'</span>).width(<span class="hljs-number">100</span>);
<span class="hljs-keyword">export</span> {};
</code></pre>
            <h3 id="t17512.5 第三方声明文件">12.5 第三方声明文件 <a
                    href="#t17512.5%20%E7%AC%AC%E4%B8%89%E6%96%B9%E5%A3%B0%E6%98%8E%E6%96%87%E4%BB%B6">
                    # </a></h3>
            <ul>
                <li>可以安装使用第三方的声明文件</li>
                <li>@types是一个约定的前缀，所有的第三方声明的类型库都会带有这样的前缀</li>
                <li>JavaScript 中有很多内置对象，它们可以在 TypeScript 中被当做声明好了的类型</li>
                <li>内置对象是指根据标准在全局作用域（Global）上存在的对象。这里的标准是指 ECMAScript 和其他环境（比如 DOM）的标准</li>
                <li>这些内置对象的类型声明文件，就包含在<a href="https://github.com/Microsoft/TypeScript/tree/master/src/lib">TypeScript
                        核心库的类型声明文件</a>中</li>
            </ul>
            <h4 id="t17612.5.1 使用jquery">12.5.1 使用jquery <a href="#t17612.5.1%20%E4%BD%BF%E7%94%A8jquery">
                    # </a></h4>
            <pre><code class="lang-js">cnpm i jquery -S
</code></pre>
            <pre><code class="lang-js"><span class="hljs-comment">//对于common.js风格的模块必须使用 import * as </span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> jQuery <span class="hljs-keyword">from</span> <span class="hljs-string">'jquery'</span>;
jQuery.ajax(<span class="hljs-string">'/user/1'</span>);
</code></pre>
            <h4 id="t17712.5.2 安装声明文件">12.5.2 安装声明文件 <a
                    href="#t17712.5.2%20%E5%AE%89%E8%A3%85%E5%A3%B0%E6%98%8E%E6%96%87%E4%BB%B6">
                    # </a></h4>
            <pre><code class="lang-js">cnpm i @types/jquery -S
</code></pre>
            <h4 id="t17812.5.3 自己编写声明文件">12.5.3 自己编写声明文件 <a
                    href="#t17812.5.3%20%E8%87%AA%E5%B7%B1%E7%BC%96%E5%86%99%E5%A3%B0%E6%98%8E%E6%96%87%E4%BB%B6">
                    # </a></h4>
            <ul>
                <li><a href="https://www.tslang.cn/docs/handbook/module-resolution.html">模块查找规则</a></li>
                <li>node_modules\@types\jquery/index.d.ts</li>
                <li>我们可以自己编写声明文件并配置<code>tsconfig.json</code></li>
            </ul>
            <h5 id="t17912.5.3.1 index.d.ts">12.5.3.1 index.d.ts <a href="#t17912.5.3.1%20index.d.ts"> #
                </a></h5>
            <p><code>types\jquery\index.d.ts</code></p>
            <pre><code class="lang-js">declare <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">jQuery</span>(<span class="hljs-params">selector:string</span>):<span class="hljs-title">HTMLElement</span>;
<span class="hljs-title">declare</span> <span class="hljs-title">namespace</span> <span class="hljs-title">jQuery</span></span>{
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ajax</span>(<span class="hljs-params">url:string</span>):<span class="hljs-title">void</span>
}
<span class="hljs-title">export</span> <span class="hljs-title">default</span> <span class="hljs-title">jQuery</span>;
</span></code></pre>
            <h5 id="t18012.5.3.2 tsconfig.json">12.5.3.2 tsconfig.json <a href="#t18012.5.3.2%20tsconfig.json"> #
                </a></h5>
            <ul>
                <li>如果配置了<code>paths</code>,那么在引入包的的时候会自动去<code>paths</code>目录里找类型声明文件</li>
                <li>在 tsconfig.json 中，我们通过 <code>compilerOptions</code> 里的 <code>paths</code> 属性来配置路径映射</li>
                <li><code>paths</code>是模块名到基于<code>baseUrl</code>的路径映射的列表</li>
            </ul>
            <pre><code class="lang-js">{
  <span class="hljs-string">"compilerOptions"</span>: {
    <span class="hljs-string">"baseUrl"</span>: <span class="hljs-string">"./"</span>,<span class="hljs-comment">// 使用 paths 属性的话必须要指定 baseUrl 的值</span>
    <span class="hljs-string">"paths"</span>: {
      <span class="hljs-string">"*"</span>:[<span class="hljs-string">"types/*"</span>]
    }
}
</code></pre>
            <pre><code class="lang-js"><span class="hljs-keyword">import</span> $ <span class="hljs-keyword">from</span> <span class="hljs-string">"jquery"</span>;
$.ajax(<span class="hljs-string">'get'</span>);
</code></pre>
            <h4 id="t18112.5.4 npm声明文件可能的位置">12.5.4 npm声明文件可能的位置 <a
                    href="#t18112.5.4%20npm%E5%A3%B0%E6%98%8E%E6%96%87%E4%BB%B6%E5%8F%AF%E8%83%BD%E7%9A%84%E4%BD%8D%E7%BD%AE">
                    # </a></h4>
            <ul>
                <li>node_modules/jquery/package.json<ul>
                        <li>"types":"types/xxx.d.ts"</li>
                    </ul>
                </li>
                <li>node_modules/jquery/index.d.ts</li>
                <li>node_modules/@types/jquery/index.d.ts</li>
                <li>typings\jquery\index.d.ts</li>
            </ul>
            <h4 id="t18212.5.5 查找声明文件">12.5.5 查找声明文件 <a
                    href="#t18212.5.5%20%E6%9F%A5%E6%89%BE%E5%A3%B0%E6%98%8E%E6%96%87%E4%BB%B6">
                    # </a></h4>
            <ul>
                <li>如果是手动写的声明文件，那么需要满足以下条件之一，才能被正确的识别</li>
                <li>给 <code>package.json</code> 中的 <code>types</code> 或 <code>typings</code> 字段指定一个类型声明文件地址</li>
                <li>在项目根目录下，编写一个 <code>index.d.ts</code> 文件</li>
                <li>针对入口文件（package.json 中的 main 字段指定的入口文件），编写一个同名不同后缀的 <code>.d.ts</code> 文件</li>
            </ul>
            <pre><code class="lang-json">{
    "name": "myLib",
    "version": "1.0.0",
    "main": "lib/index.js",
    "types": "myLib.d.ts",
}
`
</code></pre>
            <ul>
                <li>先找myLib.d.ts</li>
                <li>没有就再找index.d.ts</li>
                <li>还没有再找lib/index.d.js</li>
                <li>还找不到就认为没有类型声明了</li>
            </ul>
            <h3 id="t18312.6 扩展全局变量的类型">12.6 扩展全局变量的类型 <a
                    href="#t18312.6%20%E6%89%A9%E5%B1%95%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F%E7%9A%84%E7%B1%BB%E5%9E%8B">
                    # </a></h3>
            <h4 id="t18412.6.1 扩展局部变量类型">12.6.1 扩展局部变量类型 <a
                    href="#t18412.6.1%20%E6%89%A9%E5%B1%95%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F%E7%B1%BB%E5%9E%8B">
                    # </a></h4>
            <pre><code class="lang-js">declare <span class="hljs-keyword">var</span> <span class="hljs-built_in">String</span>: StringConstructor;
interface StringConstructor {
    <span class="hljs-keyword">new</span>(value?: any): <span class="hljs-built_in">String</span>;
    (value?: any): string;
    readonly prototype: <span class="hljs-built_in">String</span>;
}
interface <span class="hljs-built_in">String</span> {
    toString(): string;
}
</code></pre>
            <pre><code class="lang-js"><span class="hljs-comment">//扩展类的原型</span>
interface <span class="hljs-built_in">String</span> {
    double():string;
}

<span class="hljs-built_in">String</span>.prototype.double = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>+<span class="hljs-string">'+'</span>+<span class="hljs-keyword">this</span>;
}
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'hello'</span>.double());

<span class="hljs-comment">//扩展类的实例</span>
interface Window{
    <span class="hljs-attr">myname</span>:string
}
<span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">window</span>.myname);
<span class="hljs-comment">//export {} 没有导出就是全局扩展</span>
</code></pre>
            <h4 id="t18512.6.2 模块内全局扩展">12.6.2 模块内全局扩展 <a
                    href="#t18512.6.2%20%E6%A8%A1%E5%9D%97%E5%86%85%E5%85%A8%E5%B1%80%E6%89%A9%E5%B1%95">
                    # </a></h4>
            <p>types\global\index.d.ts</p>
            <pre><code class="lang-js">declare global{
    interface <span class="hljs-built_in">String</span> {
        double():string;
    }
    interface Window{
        <span class="hljs-attr">myname</span>:string
    }
}

<span class="hljs-keyword">export</span>  {}
</code></pre>
            <h3 id="t18612.7 合并声明">12.7 合并声明 <a href="#t18612.7%20%E5%90%88%E5%B9%B6%E5%A3%B0%E6%98%8E">
                    # </a></h3>
            <ul>
                <li>同一名称的两个独立声明会被合并成一个单一声明</li>
                <li>合并后的声明拥有原先两个声明的特性</li>
            </ul>
            <table>
                <thead>
                    <tr>
                        <th style="text-align:left">关键字</th>
                        <th style="text-align:left">作为类型使用</th>
                        <th style="text-align:left">作为值使用</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td style="text-align:left">class</td>
                        <td style="text-align:left">yes</td>
                        <td style="text-align:left">yes</td>
                    </tr>
                    <tr>
                        <td style="text-align:left">enum</td>
                        <td style="text-align:left">yes</td>
                        <td style="text-align:left">yes</td>
                    </tr>
                    <tr>
                        <td style="text-align:left">interface</td>
                        <td style="text-align:left">yes</td>
                        <td style="text-align:left">no</td>
                    </tr>
                    <tr>
                        <td style="text-align:left">type</td>
                        <td style="text-align:left">yes</td>
                        <td style="text-align:left">no</td>
                    </tr>
                    <tr>
                        <td style="text-align:left">function</td>
                        <td style="text-align:left">no</td>
                        <td style="text-align:left">yes</td>
                    </tr>
                    <tr>
                        <td style="text-align:left">var,let,const</td>
                        <td style="text-align:left">no</td>
                        <td style="text-align:left">yes</td>
                    </tr>
                </tbody>
            </table>
            <ul>
                <li>类既可以作为类型使用，也可以作为值使用，接口只能作为类型使用</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span></span>{
    <span class="hljs-attr">name</span>:string=<span class="hljs-string">''</span>
}
<span class="hljs-keyword">let</span> p1:Person;<span class="hljs-comment">//作为类型使用</span>
<span class="hljs-keyword">let</span> p2 = <span class="hljs-keyword">new</span> Person();<span class="hljs-comment">//作为值使用</span>

interface Animal{
    <span class="hljs-attr">name</span>:string
}
<span class="hljs-keyword">let</span> a1:Animal;
<span class="hljs-keyword">let</span> a2 = Animal;<span class="hljs-comment">//接口类型不能用作值</span>
</code></pre>
            <h4 id="t18712.7.1 合并类型声明">12.7.1 合并类型声明 <a
                    href="#t18712.7.1%20%E5%90%88%E5%B9%B6%E7%B1%BB%E5%9E%8B%E5%A3%B0%E6%98%8E">
                    # </a></h4>
            <ul>
                <li>可以通过接口合并的特性给一个第三方为扩展类型声明</li>
            </ul>
            <p>use.js</p>
            <pre><code class="lang-js">interface Animal{
    <span class="hljs-attr">name</span>:string
}
<span class="hljs-keyword">let</span> a1:Animal={<span class="hljs-attr">name</span>:<span class="hljs-string">'zhufeng'</span>,<span class="hljs-attr">age</span>:<span class="hljs-number">10</span>};
<span class="hljs-built_in">console</span>.log(a1.name);
<span class="hljs-built_in">console</span>.log(a1.age);
<span class="hljs-comment">//注意不要加export {} ,这是全局的</span>
</code></pre>
            <p>types\animal\index.d.ts</p>
            <pre><code class="lang-js">interface Animal{
    <span class="hljs-attr">age</span>:number
}
</code></pre>
            <h4 id="t18812.7.2 使用命名空间扩展类">12.7.2 使用命名空间扩展类 <a
                    href="#t18812.7.2%20%E4%BD%BF%E7%94%A8%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4%E6%89%A9%E5%B1%95%E7%B1%BB">
                    # </a></h4>
            <ul>
                <li>我们可以使用 namespace 来扩展类，用于表示内部类
                    <pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Form</span> </span>{
  <span class="hljs-attr">username</span>: Form.Item=<span class="hljs-string">''</span>;
  password: Form.Item=<span class="hljs-string">''</span>;
}
<span class="hljs-comment">//Item为Form的内部类</span>
namespace Form {
  <span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Item</span> </span>{}
}
<span class="hljs-keyword">let</span> item:Form.Item = <span class="hljs-keyword">new</span> Form.Item();
<span class="hljs-built_in">console</span>.log(item);
</code></pre>
                </li>
            </ul>
            <h4 id="t18912.7.3 使用命名空间扩展函数">12.7.3 使用命名空间扩展函数 <a
                    href="#t18912.7.3%20%E4%BD%BF%E7%94%A8%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4%E6%89%A9%E5%B1%95%E5%87%BD%E6%95%B0">
                    # </a></h4>
            <ul>
                <li>我们也可以使用 <code>namespace</code> 来扩展函数</li>
            </ul>
            <pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">greeting</span>(<span class="hljs-params">name: string</span>): <span class="hljs-title">string</span> </span>{
    <span class="hljs-keyword">return</span> greeting.words+name;
}

namespace greeting {
    <span class="hljs-keyword">export</span> <span class="hljs-keyword">let</span> words = <span class="hljs-string">"Hello,"</span>;
}

<span class="hljs-built_in">console</span>.log(greeting(<span class="hljs-string">'zhufeng'</span>))
</code></pre>
            <h4 id="t19012.7.4 使用命名空间扩展枚举类型">12.7.4 使用命名空间扩展枚举类型 <a
                    href="#t19012.7.4%20%E4%BD%BF%E7%94%A8%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4%E6%89%A9%E5%B1%95%E6%9E%9A%E4%B8%BE%E7%B1%BB%E5%9E%8B">
                    # </a></h4>
            <pre><code class="lang-js">enum Color {
    red = <span class="hljs-number">1</span>,
    yellow = <span class="hljs-number">2</span>,
    blue = <span class="hljs-number">3</span>
}

namespace Color {
    <span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> green=<span class="hljs-number">4</span>;
    <span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> purple=<span class="hljs-number">5</span>;
}
<span class="hljs-built_in">console</span>.log(Color.green)
</code></pre>
            <h4 id="t19112.7.5 扩展Store">12.7.5 扩展Store <a href="#t19112.7.5%20%E6%89%A9%E5%B1%95Store">
                    # </a></h4>
            <pre><code class="lang-js"><span class="hljs-keyword">import</span> { createStore, Store } <span class="hljs-keyword">from</span> <span class="hljs-string">'redux'</span>;
type StoreExt = Store &amp; {
    <span class="hljs-attr">ext</span>: string
}
<span class="hljs-keyword">let</span> store: StoreExt = createStore(<span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state);
store.ext = <span class="hljs-string">'hello'</span>;

</code></pre>
            <h3 id="t19212.8 生成声明文件">12.8 生成声明文件 <a
                    href="#t19212.8%20%E7%94%9F%E6%88%90%E5%A3%B0%E6%98%8E%E6%96%87%E4%BB%B6">
                    # </a></h3>
            <ul>
                <li>把TS编译成JS后丢失类型声明，我们可以在编译的时候自动生成一份JS文件</li>
            </ul>
            <pre><code class="lang-json">{
  <span class="hljs-attr">"compilerOptions"</span>: {
     <span class="hljs-attr">"declaration"</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">/* Generates corresponding '.d.ts' file.*/</span>
  }
}
</code></pre>
            <h3 id="t19312.9 类型声明实战">12.9 类型声明实战 <a
                    href="#t19312.9%20%E7%B1%BB%E5%9E%8B%E5%A3%B0%E6%98%8E%E5%AE%9E%E6%88%98">
                    # </a></h3>
            <ul>
                <li><a href="https://nodejs.org/api/events.html">events</a></li>
            </ul>
            <pre><code class="lang-js">npm link
npm link zf-events
</code></pre>
            <h4 id="t19412.9.1 index.js">12.9.1 index.js <a href="#t19412.9.1%20index.js"> # </a>
            </h4>
            <pre><code class="lang-js"><span class="hljs-keyword">import</span> { EventEmitter } <span class="hljs-keyword">from</span> <span class="hljs-string">"zf-events"</span>;
<span class="hljs-built_in">console</span>.log(EventEmitter.defaultMaxListeners);
<span class="hljs-keyword">var</span> e = <span class="hljs-keyword">new</span> EventEmitter();
e.on(<span class="hljs-string">'message'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">text:string</span>) </span>{
    <span class="hljs-built_in">console</span>.log(text)
})
e.emit(<span class="hljs-string">'message'</span>, <span class="hljs-string">'hello'</span>);
</code></pre>
            <h4 id="t19512.9.2 index.d.ts">12.9.2 index.d.ts <a href="#t19512.9.2%20index.d.ts"> # </a>
            </h4>
            <pre><code class="lang-js"><span class="hljs-keyword">export</span> type Listener = <span class="hljs-function">(<span class="hljs-params">...args: any[]</span>) =&gt;</span> <span class="hljs-keyword">void</span>;
<span class="hljs-keyword">export</span> type Type = string | symbol

<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EventEmitter</span> </span>{
   <span class="hljs-keyword">static</span> defaultMaxListeners: number;
   emit(type: Type, ...args: any[]): boolean;
   addListener(type: Type, <span class="hljs-attr">listener</span>: Listener): <span class="hljs-keyword">this</span>;
   on(type: Type, <span class="hljs-attr">listener</span>: Listener): <span class="hljs-keyword">this</span>;
   once(type: Type, <span class="hljs-attr">listener</span>: Listener): <span class="hljs-keyword">this</span>;
}
</code></pre>

        </div>
    </div>
    <div class="modal fade" id="loginModal" tabindex="-1" role="dialog" aria-labelledby="loginModalLabel">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
                            aria-hidden="true">×</span></button>
                    <h4 class="modal-title" id="loginModalLabel">请登录</h4>
                </div>
                <div class="modal-body">
                    <form>
                        <div class="form-group">
                            <label for="username" class="control-label">姓名:</label>
                            <input type="text" class="form-control" id="username" placeholder="珠峰架构VIP会员系统用户名">
                        </div>
                        <div class="form-group">
                            <label for="password" class="control-label">密码:</label>
                            <input type="text" class="form-control" id="password" placeholder="珠峰架构VIP会员系统密码">
                        </div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">登录</button>
                </div>
            </div>
        </div>
    </div>
    <script src="./typescript6/jquery.min.js.下载"></script>
    <script src="./typescript6/bootstrap.min.js.下载"></script>
    <script src=''>
        let zhufengjiagou = localStorage.getItem('zhufengjiagou');
        const host = 'http://login.zhufengpeixun.com';
        if (zhufengjiagou) {
            fetch(host + '/check', {
                method: "GET",
                mode: 'cors',
                headers: {
                    'Content-Type': 'application/json',
                    authorization: `Bearer ${zhufengjiagou}`
                }
            }).then(response => response.json()).then(res => {
                if (res.success) {

                } else {
                    $('#loginModal').modal('show')
                }
            })
        } else {
            $('#loginModal').modal('show')
        }

        $('#loginModal').on('hidden.bs.modal', function (event) {
            var modal = $(this)
            let username = modal.find('.modal-body #username').val();
            let password = modal.find('.modal-body #password').val();
            fetch(host + '/login', {
                method: "POST",
                mode: 'cors',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    username,
                    password
                })
            }).then(response => response.json()).then(res => {
                console.log(res);
                if (res.success) {
                    localStorage.setItem('zhufengjiagou', res.zhufengjiagou);
                } else {
                    window.location.href = 'http://www.zhufengpeixun.cn';
                }
            })
        })
    </script>
    <script>
        $('.warpper .page-toc ul ul li a').on('click', function () {
            $('.warpper .page-toc ul ul li a').removeClass('my-active')
            $(this).addClass('my-active')
        })
        $('.logo').on('mouseenter', function () {
            $('.nav').height('450px');
        })
        $('.nav').on('mouseleave', function () {
            $('.nav').height('80px');
        })
        $('.logo').on('click', function () {
            $('.nav').css('display', 'none');
            $('.warpper').css('padding', '0px');
        })
    </script>


</body>

</html>